
Review
- 530 installs
- 2 repo stars
- Updated July 8, 2026
- shiplightai/agent-skills
review is a Claude Code skill that orchestrates eight application review domains—security, privacy, compliance, design, resilience, performance, SEO, and GEO—into one unified pre-launch report for developers.
About
review is the Shiplight agent-skills orchestrator and single entry point for application reviews. It triages context, then loads domain playbooks from references/ for security (OWASP, auth, supply chain), privacy (PII, GDPR/CCPA), compliance (HIPAA, SOC 2, PCI-DSS), design (responsive, a11y, i18n), resilience (errors, API contracts), performance (Core Web Vitals, bundles), SEO (meta, structured data), and GEO (llms.txt, AI citation readiness). Three modes cover default triage (/review), full suite (/review --all), and targeted domain runs (/review security --quick). Use review for pre-launch readiness, post-incident planning, or any request to review an app when the needed domain is unclear.
- review
- AI & Agent Building
- AI-coding skill
Review by the numbers
- 530 all-time installs (skills.sh)
- +20 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #1,710 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/shiplightai/agent-skills --skill reviewAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 530 |
|---|---|
| repo stars | ★ 2 |
| Last updated | July 8, 2026 |
| Repository | shiplightai/agent-skills ↗ |
How do you run a full pre-launch app review?
Helps with ai & agent building tasks.
Who is it for?
Developers preparing to ship a web or mobile app who need triaged, multi-domain review without manually picking security, SEO, or compliance skills.
Skip if: Teams needing only Shiplight YAML test triage or browser UI verification—use shiplight triage or verify skills instead.
When should I use this skill?
User asks to review an app pre-launch, check readiness across domains, or says review my app without specifying security vs SEO
What you get
Unified review report with domain findings from security, privacy, compliance, design, resilience, performance, SEO, and GEO
- Unified multi-domain review report
- Per-domain findings and recommendations
By the numbers
- Orchestrates 8 application review domains with dedicated reference playbooks
- Supports 3 invocation modes: triage, --all full suite, and targeted domain review
Files
Review Orchestrator
The single entry point for application reviews. It triages what matters, then runs one or more domain reviews and merges them into a unified report. Each domain lives in references/<domain>.md and is loaded only when selected.
When to use
- User wants a review but isn't sure which kind
- Pre-launch readiness assessment
- Post-incident review planning
- A targeted request for one domain ("check my app's security", "review SEO")
Modes
- Triage (default,
/review) — ask context questions, recommend a plan, run it. - Full suite (
/review --all) — run every applicable domain. - Targeted (
/review <domain>) — jump straight into one domain, skipping
triage. E.g. /review security, /review seo. Accepts an optional depth flag (--quick / --thorough).
Domains
Each row maps to a reference file. Load the file only when the domain is selected.
| Domain | Reference | Run it when… (trigger signals) |
|---|---|---|
| security | references/security.md | auth/login changes, sensitive data, OWASP, headers/CORS/CSP, supply chain |
| privacy | references/privacy.md | collects PII, tracking/analytics, consent banners, GDPR/CCPA |
| compliance | references/compliance.md | regulated industry, audit prep, HIPAA/SOC 2/PCI-DSS/GDPR, payments or health data |
| design | references/design.md | UI shipping without a designer, responsive, accessibility, typography, i18n |
| resilience | references/resilience.md | error handling, network/API failures, empty/edge states, degradation |
| performance | references/performance.md | slow pages, Core Web Vitals, bundle size, runtime/render perf |
| seo | references/seo.md | public site, meta tags, structured data, crawlability, sitemaps |
| geo | references/geo.md | discovered via AI assistants, LLM citation readiness, llms.txt, entity clarity |
Shared conventions (phases, scoring, confidence, severity, output paths) live in references/report-format.md — every domain follows them.
Steps
1. Gather context
- Read the project: tech stack, framework,
package.json, routes, components. - Check
git difffor recent changes. - Look for existing reports in
shiplight/reports/. - Auto-detect compliance markers (HIPAA/PHI, PCI/payment fields, GDPR/cookie consent).
If invoked as /review <domain>, skip to step 4 for that domain.
2. Ask targeted questions (max 4)
One at a time, with auto-detected defaults:
1. What type of application? (SaaS, healthcare, fintech, e-commerce, internal tool, marketing site, API-only) 2. What triggered this review? (pre-launch, new feature, dependency update, security incident, audit prep, routine) 3. Any compliance requirements? (none, HIPAA, SOC2, PCI-DSS, GDPR, multiple) — auto-detect from codebase 4. Specific concerns? (open-ended, optional)
3. Generate review plan
Categorize each applicable domain as CRITICAL (must run), RECOMMENDED (meaningful value), or OPTIONAL (nice to have), with estimated depth (quick / standard / thorough).
SEO vs GEO prioritization by product type:
| Product type | SEO | GEO |
|---|---|---|
| Developer tools, API products, SaaS | RECOMMENDED | CRITICAL |
| E-commerce, local business, marketplace | CRITICAL | OPTIONAL |
| Content/media, documentation, blog | CRITICAL | CRITICAL |
| Internal tools | — | — |
Present a decision matrix:
| Review | Priority | Rationale | Depth |
|---|---|---|---|
| security | CRITICAL | New auth feature + SaaS app | thorough |
| privacy | CRITICAL | Handles user PII, GDPR applies | standard |
| … |
4. Execute
Ask: "Run all CRITICAL reviews now? [Y/n] Or pick specific ones."
For each selected domain, read `references/<domain>.md` and follow its five phases, applying references/report-format.md for scoring, severity, and output paths. Run domains sequentially; show a brief summary after each before moving on.
5. Unified report
After the selected domains complete, merge their per-domain reports into one, saved to shiplight/reports/review-{date}.md:
- Overall readiness score (0–10) and per-domain scores
- Top 5 findings across all domains, by severity
- Regression test summary (total YAML tests generated, in
shiplight/tests/)
Tips
- Run
/reviewbefore every major launch. /review <domain>is the fast path when you already know what you need.- Reports accumulate in
shiplight/reports/— the orchestrator can show trends. - YAML regression tests from reviews accumulate in
shiplight/tests/.
Compliance Review
Evaluate your application against industry-specific regulatory requirements. This review translates dense compliance frameworks into concrete, testable technical checks — and validates them through browser-based testing. Non-compliance can result in severe fines, legal action, and loss of business.
When to use
Use this review when:
- Building applications for regulated industries (healthcare, finance, government)
- Preparing for a compliance audit (SOC 2, HIPAA, PCI-DSS)
- Adding payment processing or health data features
- Expanding to GDPR-regulated markets
- After infrastructure or architecture changes that affect data handling
Standards Referenced
- HIPAA — Health Insurance Portability and Accountability Act (Technical Safeguards §164.312)
- SOC 2 — Service Organization Control (Trust Service Criteria)
- PCI-DSS v4.0 — Payment Card Industry Data Security Standard
- GDPR — General Data Protection Regulation (Technical Measures)
Phase Overview
Phase 1: EDUCATE → Compliance context and applicable frameworks
Phase 2: SCOPE → Determine which frameworks apply, identify regulated data
Phase 3: ANALYZE → Browser-based checks against framework requirements
Phase 4: REPORT → Findings mapped to specific regulatory sections
Phase 5: REMEDIATE → Fix guidance + YAML regression tests for continuous compliance---
Phase 1: Educate
Why this matters: HIPAA violations: up to $1.9M per violation category per year. PCI-DSS non-compliance: $5,000-$100,000/month in fines plus liability for breaches. SOC 2 failures: loss of enterprise customers who require it. GDPR: up to 4% of global annual revenue. These aren't theoretical — enforcement is active and increasing.
Compliance frameworks are large documents. This review extracts the technical requirements testable in a web application — not the organizational/procedural requirements (policies, training, vendor management) that require human process review.
---
Phase 2: Scope
Determine applicable frameworks
1. Auto-detect from codebase:
- Health data handling (HIPAA indicators: HL7, FHIR, patient records, PHI references)
- Payment processing (PCI-DSS indicators: Stripe, Braintree, credit card fields, payment forms)
- EU user data (GDPR indicators: consent banners, cookie notices, EU deployments)
- Audit logging (SOC 2 indicators: audit trail, event logging, access logs)
2. Ask the user:
- Which frameworks apply? (auto-detected, confirm)
- [ ] HIPAA — healthcare / protected health information
- [ ] SOC 2 — enterprise SaaS / customer data
- [ ] PCI-DSS — payment card data
- [ ] GDPR — EU personal data
- [ ] Other (specify)
- Target URL: Where is the app running?
- Regulated data types: What regulated data does the app handle? (auto-detected)
- Test credentials: Accounts with access to regulated data for testing
3. Map regulated data flows:
- Where regulated data enters the system (forms, APIs, imports)
- Where it's displayed (dashboards, reports, exports)
- Where it's stored client-side (if anywhere)
- Where it's transmitted (API endpoints, third-party services)
---
Phase 3: Analyze
Run only the sections applicable based on Phase 2 scoping. Open a browser session with new_session using record_evidence: true.
HIPAA Technical Safeguards (HIP)
Applicable when: application handles Protected Health Information (PHI).
| Check ID | Check | HIPAA Section | Method |
|---|---|---|---|
| HIP-01 | PHI not displayed without authentication | §164.312(d) | Access PHI pages without auth, verify 401/redirect |
| HIP-02 | Session auto-timeout after inactivity | §164.312(a)(2)(iii) | Wait for idle period, verify session expiration |
| HIP-03 | PHI not in URL parameters | §164.312(e)(1) | Navigate PHI pages, check URLs |
| HIP-04 | PHI not in browser console/logs | §164.312(b) | Check get_browser_console_logs for PHI patterns |
| HIP-05 | PHI not cached in browser storage | §164.312(a)(2)(iv) | Check localStorage, sessionStorage for PHI |
| HIP-06 | PHI transmitted over HTTPS only | §164.312(e)(1) | Verify all PHI API calls use HTTPS |
| HIP-07 | Audit trail for PHI access | §164.312(b) | Access PHI, verify audit log entry exists |
| HIP-08 | Role-based access to PHI | §164.312(a)(1) | Test PHI access with different user roles |
| HIP-09 | PHI display has minimum necessary principle | §164.502(b) | Check if UI shows only needed PHI fields |
| HIP-10 | Emergency access procedure exists | §164.312(a)(2)(ii) | Check for break-glass or emergency access UI |
| HIP-11 | No PHI in error messages | §164.312(b) | Trigger errors on PHI pages, check messages |
| HIP-12 | Logout fully terminates PHI access | §164.312(a)(2)(iii) | Logout, back button, check no PHI visible |
Browser validation: Navigate to pages with PHI. Test access controls. Check for PHI in URLs, storage, console. Test session timeout by waiting. Test logout completeness.
SOC 2 Trust Service Criteria (SOC)
Applicable when: enterprise SaaS handling customer data.
| Check ID | Check | SOC 2 Criteria | Method |
|---|---|---|---|
| SOC-01 | Authentication required for all data access | CC6.1 | Access data pages without auth |
| SOC-02 | Strong password requirements enforced | CC6.1 | Test signup/password change with weak passwords |
| SOC-03 | MFA available for user accounts | CC6.1 | Check account security settings for MFA option |
| SOC-04 | Session management is secure | CC6.1 | Check cookie flags, timeout, logout behavior |
| SOC-05 | Data is encrypted in transit | CC6.7 | Verify HTTPS everywhere, check for mixed content |
| SOC-06 | Access is logged (audit trail) | CC7.2 | Perform actions, verify audit log entries |
| SOC-07 | Failed login attempts are monitored | CC7.2 | Multiple failed logins, check for alerting/lockout |
| SOC-08 | User permissions are role-based | CC6.3 | Test different roles, verify appropriate access |
| SOC-09 | Data deletion is available | CC6.5 | Test account/data deletion functionality |
| SOC-10 | System status page or health endpoint | CC7.1 | Check for status page or /health endpoint |
| SOC-11 | Error handling doesn't leak internal details | CC7.4 | Trigger errors, check for stack traces |
| SOC-12 | Change management evident (versioning) | CC8.1 | Check for version info, changelog |
Browser validation: Test authentication boundaries, password policies, MFA flows, role-based access, audit logging visibility.
PCI-DSS v4.0 (PCI)
Applicable when: application processes, stores, or transmits cardholder data.
| Check ID | Check | PCI-DSS Req | Method |
|---|---|---|---|
| PCI-01 | Credit card numbers never fully displayed | 3.4 | View saved cards, verify masking (show last 4 only) |
| PCI-02 | CVV never stored or displayed after authorization | 3.3.2 | Check storage, API responses for CVV |
| PCI-03 | Payment form uses HTTPS | 4.1 | Verify payment page URL and all resources |
| PCI-04 | Payment form is on compliant iframe/redirect | SAQ A | Check if using Stripe Elements, PayPal, or similar |
| PCI-05 | No cardholder data in URL parameters | 4.2 | Check URLs during payment flow |
| PCI-06 | No cardholder data in client storage | 3.2 | Check localStorage, sessionStorage, cookies |
| PCI-07 | No cardholder data in console logs | 3.2 | Check get_browser_console_logs during payment |
| PCI-08 | Payment form prevents autocomplete on card fields | Best practice | Check autocomplete="off" on sensitive fields |
| PCI-09 | Strong authentication for payment admin | 8.3 | Verify admin/payment management requires strong auth |
| PCI-10 | Access to cardholder data is role-restricted | 7.1 | Test access to payment data with non-admin users |
| PCI-11 | Payment error messages don't reveal card details | 3.2 | Trigger payment errors, check messages |
| PCI-12 | CSP prevents unauthorized scripts on payment pages | 6.4.3 | Check CSP header on payment pages specifically |
Browser validation: Walk through the payment flow. Check card display masking. Inspect storage and console for cardholder data. Verify payment form is iframe/hosted (SAQ A compliance).
GDPR Technical Requirements (GDPR)
Applicable when: application handles EU personal data. (Note: privacy-specific checks are in the privacy review — this section covers GDPR's technical/compliance obligations.)
| Check ID | Check | GDPR Article | Method |
|---|---|---|---|
| GDPR-01 | Consent collected before data processing | Art. 6, 7 | Load page, check if processing occurs before consent |
| GDPR-02 | Privacy policy is accessible and current | Art. 13, 14 | Find and verify privacy policy page |
| GDPR-03 | Data subject access request mechanism exists | Art. 15 | Find data export/download feature |
| GDPR-04 | Right to erasure is implemented | Art. 17 | Find and test account deletion |
| GDPR-05 | Data portability (export in standard format) | Art. 20 | Test data export, verify format (JSON/CSV) |
| GDPR-06 | Consent withdrawal is as easy as giving consent | Art. 7(3) | Compare consent-giving vs withdrawal UX |
| GDPR-07 | Age verification for minors (if applicable) | Art. 8 | Check for age gate or parental consent |
| GDPR-08 | Data processing records accessible | Art. 30 | Check for processing activity documentation |
| GDPR-09 | Data breach notification mechanism | Art. 33, 34 | Check for incident response documentation |
| GDPR-10 | Cross-border transfer safeguards | Art. 44-49 | Check where third-party services are hosted |
Browser validation: Test consent flows, data export, account deletion, privacy policy accessibility. Check third-party script origins for cross-border transfer concerns.
---
Phase 4: Report
Generate a structured report saved to shiplight/reports/compliance-review-{date}.md:
# Compliance Review Report
**Date:** {date}
**URL:** {url}
**Frameworks evaluated:** {HIPAA, SOC 2, PCI-DSS, GDPR}
**Regulated data types:** {PHI, cardholder data, EU personal data}
## Overall Compliance Score: {X}/10 | Confidence: {X}%
## Framework Scores
| Framework | Score | Pass | Fail | N/A | Critical Gaps |
|-----------|-------|------|------|-----|---------------|
| HIPAA | 6/10 | 8 | 3 | 1 | Session timeout, PHI in URL |
| SOC 2 | 7/10 | 9 | 2 | 1 | No MFA, weak audit trail |
| PCI-DSS | 8/10 | 10 | 1 | 1 | Card data in console |
| GDPR | 5/10 | 5 | 4 | 1 | Consent, data export, erasure |
## Compliance Status by Check
(Full table of all checks with PASS/FAIL/N-A status, evidence, and confidence)
## Critical Non-Compliance Items
(Findings that could result in regulatory action, ordered by risk)
## Audit Preparation Checklist
- [ ] Fix all CRITICAL findings
- [ ] Fix all HIGH findings
- [ ] Document accepted risks for MEDIUM findings
- [ ] Run YAML regression tests before audit date
- [ ] Prepare evidence documentation from this reportConfidence Scoring
- 90-100%: Browser-validated, compliance violation confirmed (e.g., PHI visible without auth, card number in console)
- 70-89%: Strong evidence from inspection (e.g., missing header, no timeout behavior)
- 50-69%: Architectural concern based on code patterns (e.g., audit logging might be incomplete)
- Below 50%: Don't report — compliance findings must be substantiated
---
Phase 5: Remediate
1. Fix guidance (example)
#### HIP-02: No session auto-timeout
**Regulation:** HIPAA §164.312(a)(2)(iii) — Automatic logoff
**Risk:** Unattended sessions with PHI visible
**Current:** Sessions persist indefinitely
**Fix:** Implement idle timeout (HIPAA recommends ≤15 minutes for PHI access)
- Add client-side idle detection (mouse, keyboard events)
- Server-side session expiry as backup
- Show warning dialog at 12 minutes
- Auto-logout and clear screen at 15 minutes2. YAML regression test
- name: hip-02-session-auto-timeout
description: Verify session auto-timeout for HIPAA compliance
severity: critical
standard: HIPAA-164.312(a)(2)(iii)
steps:
- URL: /login
- intent: Log in with test credentials
action: fill
locator: "getByLabel('Email')"
value: "test@example.com"
- intent: Enter password
action: fill
locator: "getByLabel('Password')"
value: "testpass123"
- intent: Submit login form
action: click
locator: "getByRole('button', { name: 'Sign in' })"
- WAIT_UNTIL: Dashboard with PHI is visible
timeout_seconds: 15
- VERIFY: Session timeout warning appears after inactivity period
timeout_seconds: 900
- VERIFY: User is automatically logged out after timeout expires
timeout_seconds: 300Save all YAML tests to shiplight/tests/compliance-review.test.yaml.
---
Depth Levels
- `--quick`: Critical checks only — authentication boundaries + data exposure. ~3 minutes.
- default: Full applicable framework. ~10-15 minutes.
- `--thorough`: All checks + multi-role testing + edge cases + documentation review. ~25-40 minutes.
Tips
- Run the compliance review specific to your framework: "run HIPAA checks only"
- Compliance requires evidence — use
record_evidence: trueandgenerate_html_reportfor audit documentation - YAML regression tests from this review serve as continuous compliance monitoring
- This review covers technical requirements only — organizational requirements (policies, training) need human review
- For privacy-specific concerns, complement with the privacy review (
/review privacy) - For security-specific concerns, complement with the security review (
/review security) - Close session with
close_sessionand usegenerate_html_reportfor evidence
Design Review
Evaluate your application's visual quality and usability against established design standards. This review catches issues that typically require a trained designer's eye — responsive breakpoints, accessibility compliance, visual hierarchy, spacing consistency, and internationalization readiness.
When to use
Use this review when:
- Shipping UI without a designer reviewing it
- Before a launch or demo
- After significant UI changes or redesigns
- Checking accessibility compliance (WCAG 2.1 AA)
- Validating responsive behavior across devices
Standards Referenced
- WCAG 2.1 Level AA — Web Content Accessibility Guidelines
- Material Design / Human Interface Guidelines — spacing, touch targets, typography scales
- ISO 9241-110 — Interaction principles (suitability, self-descriptiveness, conformity)
- APCA — Advanced Perceptual Contrast Algorithm (next-gen contrast)
Phase Overview
Phase 1: EDUCATE → Brief context on what we check and why
Phase 2: SCOPE → Identify pages, breakpoints, and focus areas
Phase 3: ANALYZE → Browser-based checks with evidence capture
Phase 4: REPORT → Findings with screenshots, scores, confidence
Phase 5: REMEDIATE → Fix guidance + YAML regression tests---
Phase 1: Educate
Why this matters: 94% of first impressions are design-related. Poor visual quality erodes trust even when functionality is correct. Accessibility issues affect 15-20% of users and carry legal risk (ADA lawsuits increased 300% since 2018).
This review checks your app against objective, measurable design criteria — not subjective taste. Every finding references a specific standard.
---
Phase 2: Scope
Gather context
1. Auto-detect — scan the project for:
- Framework (React, Vue, Next.js, etc.)
- CSS approach (Tailwind, CSS modules, styled-components, etc.)
- Design system in use (if any)
- Route structure → list of pages
- Existing a11y tooling (eslint-plugin-jsx-a11y, axe-core, etc.)
2. Ask the user (one at a time, with auto-detected defaults):
- Target URL: Where is the app running? (auto-detect dev server)
- Key pages: Which pages matter most? (recommend top 3-5 from routes)
- Target devices: Desktop only? Mobile-first? Both? (default: both)
- Brand guidelines: Any specific colors, fonts, or design system? (default: evaluate against general best practices)
- Focus areas: Any known concerns? (optional)
3. Define breakpoints to test:
- Mobile: 375px (iPhone SE), 390px (iPhone 14)
- Tablet: 768px (iPad)
- Desktop: 1280px, 1920px
- (Adjust based on user's target audience)
---
Phase 3: Analyze
Open a browser session with new_session using record_evidence: true. For each page in scope, run the following check categories.
Category A: Responsive Design (RES)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| RES-01 | Viewport meta tag present | Mobile best practice | Inspect <meta name="viewport"> |
| RES-02 | No horizontal overflow at any breakpoint | Responsive design | Resize viewport, check for horizontal scrollbar |
| RES-03 | Touch targets ≥ 48x48px on mobile | WCAG 2.5.8 / Material Design | Measure interactive element sizes at mobile breakpoint |
| RES-04 | Text remains readable without zoom at 375px | WCAG 1.4.4 | Check font sizes ≥ 16px for body text on mobile |
| RES-05 | Navigation is accessible at all breakpoints | Usability | Verify nav collapses/adapts, hamburger menu works |
| RES-06 | Images scale appropriately | Responsive images | Check for srcset/sizes or CSS containment |
| RES-07 | No content truncation without indication | Usability | Check text overflow, ellipsis with tooltip or expand |
| RES-08 | Form inputs are usable on mobile | Usability | Check input sizes, proper input types (tel, email) |
Browser validation: For each breakpoint, use act to resize the viewport, then inspect_page to capture DOM and screenshot. Check for overflow elements, measure sizes via JavaScript.
Category B: Accessibility (A11Y)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| A11Y-01 | Color contrast ratio ≥ 4.5:1 (normal text) | WCAG 1.4.3 AA | Extract computed colors, calculate ratio |
| A11Y-02 | Color contrast ratio ≥ 3:1 (large text ≥ 18pt) | WCAG 1.4.3 AA | Same as above for large text |
| A11Y-03 | All images have alt text | WCAG 1.1.1 | Check <img> elements for alt attribute |
| A11Y-04 | Form inputs have associated labels | WCAG 1.3.1 | Check <label for=""> or aria-label |
| A11Y-05 | Heading hierarchy is logical (h1→h2→h3) | WCAG 1.3.1 | Extract heading levels, check sequence |
| A11Y-06 | Focus is visible on all interactive elements | WCAG 2.4.7 | Tab through elements, check focus ring visibility |
| A11Y-07 | Keyboard navigation works (Tab, Enter, Escape) | WCAG 2.1.1 | Navigate entire page via keyboard |
| A11Y-08 | Skip navigation link present | WCAG 2.4.1 | Check for skip-to-content link |
| A11Y-09 | ARIA roles used correctly | WCAG 4.1.2 | Check for misused/redundant ARIA |
| A11Y-10 | Page has lang attribute | WCAG 3.1.1 | Check <html lang=""> |
| A11Y-11 | Modal focus trapping works | WCAG 2.4.3 | Open modal, verify Tab stays within |
| A11Y-12 | Error messages are associated with inputs | WCAG 3.3.1 | Check aria-describedby or aria-errormessage |
| A11Y-13 | Reduced motion respected | WCAG 2.3.3 | Check for prefers-reduced-motion media query |
| A11Y-14 | No seizure-inducing content (>3 flashes/sec) | WCAG 2.3.1 | Visual inspection of animations |
Browser validation: Use inspect_page to extract the DOM. Run JavaScript via act to compute contrast ratios, check ARIA attributes, extract heading hierarchy. Use keyboard navigation (Tab, Enter, Escape) to test focus management.
Category C: Visual Consistency (VIS)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| VIS-01 | Consistent spacing scale | Design systems | Extract margins/paddings, check for consistent scale (4px/8px grid) |
| VIS-02 | Typography scale is consistent | Typographic hierarchy | Extract font sizes, check for consistent ratio/scale |
| VIS-03 | Color palette is limited and intentional | Design best practice | Extract all used colors, flag if >10 unique non-gray colors |
| VIS-04 | Interactive elements have consistent styling | Consistency | Compare button styles, link styles across pages |
| VIS-05 | Alignment grid is consistent | Layout | Check for misaligned elements that break the visual grid |
| VIS-06 | Loading states exist for async operations | UX best practice | Trigger async actions, verify loading indicators |
| VIS-07 | Empty states are handled | UX best practice | Navigate to pages with no data, check for meaningful empty states |
| VIS-08 | Error states are styled consistently | UX best practice | Trigger validation errors, check styling |
| VIS-09 | Dark mode consistency (if applicable) | Design systems | Toggle dark mode, check for un-themed elements |
Browser validation: Use JavaScript to extract computed styles, compare across elements and pages. Screenshot comparison between pages for visual consistency.
Category D: Typography & Readability (TYP)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| TYP-01 | Body text 16-20px | Readability research | Extract computed font-size |
| TYP-02 | Line height 1.4-1.6 for body text | Readability | Extract computed line-height |
| TYP-03 | Line length 45-75 characters | Readability (Bringhurst) | Measure character count per line |
| TYP-04 | Font loading strategy (FOUT/FOIT prevention) | Web performance | Check font-display CSS, preload hints |
| TYP-05 | Sufficient hierarchy levels (≥3 distinct sizes) | Typography | Extract and count distinct heading sizes |
| TYP-06 | Text is left-aligned (not justified) for body | Readability | Check text-align for body paragraphs |
Category E: Internationalization Readiness (I18N)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| I18N-01 | No hardcoded strings in components | i18n best practice | Scan source code for string literals in JSX/templates |
| I18N-02 | Layout handles text expansion (+30%) | i18n design | Inject longer text strings, check for overflow |
| I18N-03 | RTL layout support (if applicable) | i18n | Toggle dir="rtl", check layout adaptation |
| I18N-04 | Date/number formatting uses locale | i18n | Check for hardcoded date/number formats |
| I18N-05 | Font stack includes CJK/Unicode fallbacks | i18n typography | Check font-family declarations |
| I18N-06 | Icons/images don't contain text | i18n | Visual inspection of image content |
Browser validation: Use JavaScript to modify dir attribute, inject longer text, change locale settings. Screenshot at each state.
---
Phase 4: Report
Generate a structured report saved to shiplight/reports/design-review-{date}.md:
# Design Review Report
**Date:** {date}
**URL:** {url}
**Pages reviewed:** {list}
**Breakpoints tested:** {list}
## Overall Score: {X}/10 | Confidence: {X}%
## Score Breakdown
| Category | Score | Findings |
|----------|-------|----------|
| Responsive (RES) | 7/10 | 2 high, 1 medium |
| Accessibility (A11Y) | 5/10 | 1 critical, 3 high |
| Visual Consistency (VIS) | 8/10 | 1 medium |
| Typography (TYP) | 9/10 | 1 low |
| i18n Readiness (I18N) | 6/10 | 2 medium |
## Findings
### CRITICAL
#### A11Y-01: Insufficient color contrast on primary buttons
- **Standard:** WCAG 1.4.3 AA (minimum 4.5:1)
- **Finding:** Primary button (#4A90D2 on #FFFFFF) has contrast ratio 3.1:1
- **Evidence:** [screenshot with annotation]
- **Pages affected:** All pages with primary CTA
- **Confidence:** 97%
### HIGH
...
### MEDIUM
...
### LOW / INFO
...Confidence Scoring
- 90-100%: Browser-validated, measured programmatically (contrast ratio calculated, element size measured)
- 70-89%: Strong evidence from DOM inspection, screenshot supports finding
- 50-69%: Heuristic-based, may vary by context (e.g., "spacing looks inconsistent")
- Below 50%: Don't report
---
Phase 5: Remediate
For each finding, provide:
1. Fix guidance
#### A11Y-01: Insufficient color contrast
**File:** src/components/Button.tsx:23
**Current:** `background: #4A90D2` (contrast 3.1:1 against white)
**Fix:** `background: #2563EB` (contrast 4.8:1 against white) — maintains blue hue, meets AA
**Alternative:** `background: #1D4ED8` (contrast 7.1:1) — meets AAA2. YAML regression test
- name: a11y-01-button-contrast
description: Verify primary button meets WCAG AA contrast ratio
severity: critical
standard: WCAG-1.4.3-AA
steps:
- URL: /
- VERIFY: Primary action buttons have sufficient color contrast (minimum 4.5:1 ratio for normal text)
timeout_seconds: 15Save all YAML tests to shiplight/tests/design-review.test.yaml.
---
Tips
- Use
inspect_pageto read the DOM first — it's cheaper than screenshots and provides element indices foract. - For contrast checking, use JavaScript via
actwithwindow.getComputedStyle()to extract actual rendered colors. - Test keyboard navigation by using
actwith keyboard actions (Tab, Enter, Escape, Arrow keys). - Run this review at multiple breakpoints — many issues only appear at specific viewport sizes.
- For i18n text expansion testing, use
actwith JavaScript to modifytextContentto longer strings. - Close the session with
close_sessionand usegenerate_html_reportfor a shareable evidence report.
GEO Review
Evaluate how well your application and content are optimized for AI-powered search and answer engines — ChatGPT, Perplexity, Google AI Overviews, Claude, and other generative AI systems that cite web sources. Traditional SEO gets you ranked in a link list; GEO gets you cited in AI-generated answers.
When to use
Use this review when:
- Your product is discovered through AI assistants (developer tools, SaaS, APIs)
- You want to appear in Google AI Overviews
- Users find your product by asking AI "what's the best X for Y?"
- You publish documentation, guides, or educational content
- Your competitors are showing up in AI answers and you're not
- Building thought leadership content that AI should reference
- Launching a new product where AI-driven discovery matters
Why GEO Matters Now
- 40% of Gen Z uses TikTok and AI chatbots instead of Google for search (Adobe 2024)
- Google AI Overviews now appear for ~30% of search queries, pushing traditional results below the fold
- Perplexity processes 100M+ queries/month, citing web sources in every answer
- ChatGPT with browsing and search is becoming a primary research tool
- AI systems don't rank links — they select and cite sources based on different signals than traditional SEO
- Being the source an AI quotes is the new "position #1"
Standards & Frameworks Referenced
- GEO research (Georgia Tech / Princeton / IIT Delhi, 2024) — "GEO: Generative Engine Optimization"
- Google E-E-A-T — Experience, Expertise, Authoritativeness, Trustworthiness
- Schema.org — Structured data for entity understanding
- llms.txt — Emerging standard for AI crawler instructions (similar to robots.txt for LLMs)
- Retrieval-Augmented Generation (RAG) — How AI systems fetch and cite content
Phase Overview
Phase 1: EDUCATE → How AI search works differently from traditional search
Phase 2: SCOPE → Identify content types, target queries, AI visibility goals
Phase 3: ANALYZE → Content analysis + browser-based AI search validation
Phase 4: REPORT → Findings with citation gap analysis and confidence scores
Phase 5: REMEDIATE → Fix guidance + YAML regression tests---
Phase 1: Educate
How AI search is different: Traditional search engines crawl, index, and rank pages by relevance signals (backlinks, keywords, authority). AI answer engines do something fundamentally different — they retrieve content, understand it semantically, and synthesize answers by selecting the most citation-worthy sources. Your content needs to be clear, specific, authoritative, and directly answerable to be selected.
Key insight: AI systems prefer content that makes specific, verifiable claims with supporting evidence. Vague marketing copy is ignored. Concrete statements with data, comparisons, and clear structure get cited.
---
Phase 2: Scope
Gather context
1. Auto-detect from codebase/content:
- Content pages (docs, blog, landing pages, about, pricing, FAQ)
- Existing structured data (JSON-LD, Schema.org)
- Content management approach (static, CMS, MDX, etc.)
- llms.txt presence
- Sitemap and content organization
- Author/expertise signals
- Publication dates and freshness signals
2. Ask the user (one at a time):
- Product type: What does your product/site do? (needed to understand AI query context)
- Target URL: Where is the content published?
- Target AI queries: What questions should AI answer with your content? (e.g., "best CI/CD tool for startups", "how to implement OAuth in Node.js")
- Competitors: Who else shows up when AI answers these queries? (optional but valuable)
- Content goals: Documentation? Thought leadership? Product discovery? All of the above?
3. Map content landscape:
- Key content pages and their purpose
- Target queries each page should satisfy
- Current AI citation status (test a few queries in ChatGPT/Perplexity)
- Content gaps vs competitors
---
Phase 3: Analyze
Open a browser session with new_session using record_evidence: true. Run all applicable check categories.
Category A: Content Citation-Worthiness (CITE)
| Check ID | Check | Principle | Method |
|---|---|---|---|
| CITE-01 | Content contains specific, verifiable claims | GEO research | Scan pages for concrete statements with data/numbers |
| CITE-02 | Statistics and original data are present | GEO research | Check for unique numbers, benchmarks, research findings |
| CITE-03 | Content directly answers target queries | RAG retrieval | Match content against target queries — does it contain direct answers? |
| CITE-04 | Claims have supporting evidence or citations | E-E-A-T | Check for source references, links, data attribution |
| CITE-05 | Content is specific (not generic/vague) | GEO research | Analyze content for specificity vs marketing fluff |
| CITE-06 | Comparison content exists (vs alternatives) | AI preference | Check for "X vs Y" or comparison tables that AI can cite |
| CITE-07 | Content has clear, quotable summary sentences | Citation format | Check if key paragraphs start with citable claims |
| CITE-08 | Unique perspective or data (not regurgitated) | E-E-A-T | Assess originality — does this add something AI can't already synthesize? |
| CITE-09 | Content demonstrates first-hand experience | E-E-A-T (Experience) | Check for case studies, personal experience, real examples |
| CITE-10 | Technical accuracy and depth | E-E-A-T (Expertise) | Assess whether content goes beyond surface level |
Browser validation: Navigate to content pages. Extract text content. Analyze for claim density, statistics, quotable statements. Compare against target queries for direct answer matching.
Category B: Content Structure for AI Retrieval (STRUCT)
| Check ID | Check | Principle | Method |
|---|---|---|---|
| STRUCT-01 | Clear heading hierarchy maps to questions | RAG chunking | Check if H2/H3 headings are question-shaped or topic-clear |
| STRUCT-02 | FAQ sections with direct Q&A format | AI preference | Check for FAQ sections, question-answer pairs |
| STRUCT-03 | Definition/explanation paragraphs lead with the answer | Retrieval | Check if paragraphs front-load the key claim (inverted pyramid) |
| STRUCT-04 | Tables and structured comparisons present | AI preference | Check for HTML tables with clear headers |
| STRUCT-05 | Content is chunked into digestible sections (300-500 words) | RAG chunking | Measure section lengths between headings |
| STRUCT-06 | Lists used for multi-point information | AI preference | Check for ordered/unordered lists for multi-step or multi-item content |
| STRUCT-07 | Code examples are complete and runnable (for technical content) | Developer experience | Check code blocks for completeness and language tags |
| STRUCT-08 | TL;DR or summary at top of long content | Retrieval | Check for executive summary or key takeaways section |
Browser validation: Extract heading structure, count FAQ patterns, measure section lengths, check for tables and lists via DOM inspection.
Category C: Authority & Trust Signals (AUTH)
| Check ID | Check | Principle | Method |
|---|---|---|---|
| AUTH-01 | Author information present (name, bio, credentials) | E-E-A-T | Check for author bylines, about sections |
| AUTH-02 | Organization/brand identity clear | Entity recognition | Check for About page, consistent branding |
| AUTH-03 | Publication and update dates visible | Freshness | Check for date metadata on content pages |
| AUTH-04 | Sources and references cited | E-E-A-T | Check for outbound links to authoritative sources |
| AUTH-05 | Testimonials/social proof present | Trust | Check for customer quotes, logos, case studies |
| AUTH-06 | Professional contact information available | Trust | Check for contact page, physical address, support channels |
| AUTH-07 | Content recency (updated within last 12 months) | Freshness | Check publish/update dates |
| AUTH-08 | Domain authority indicators (established site) | E-E-A-T | Check site age, about page depth, team page |
Browser validation: Navigate to content pages, about page, author pages. Extract dates, author info, citation links.
Category D: Technical AI Discoverability (TECH)
| Check ID | Check | Principle | Method |
|---|---|---|---|
| TECH-01 | llms.txt present at site root | AI crawler standard | Fetch /llms.txt, check format and content |
| TECH-02 | llms-full.txt with detailed content (if applicable) | AI crawler standard | Fetch /llms-full.txt |
| TECH-03 | JSON-LD structured data with rich entity info | Schema.org | Check for Organization, Product, Article, FAQ schema |
| TECH-04 | Content accessible without JavaScript | RAG crawling | Disable JS, check if content renders |
| TECH-05 | Clean, semantic HTML (not framework soup) | Crawlability | Check for meaningful tags vs div-heavy DOM |
| TECH-06 | robots.txt allows AI crawlers | Discoverability | Check for GPTBot, ClaudeBot, PerplexityBot, Bingbot rules |
| TECH-07 | Sitemap includes content pages with lastmod | Discoverability | Check sitemap for content pages and dates |
| TECH-08 | Open Graph tags help AI understand content | Social + AI | Check OG tags for accurate content description |
| TECH-09 | API documentation is machine-readable (if applicable) | Developer GEO | Check for OpenAPI spec, API reference format |
| TECH-10 | Content is not behind authentication walls | RAG access | Verify key content is publicly accessible |
Browser validation: Fetch llms.txt, check robots.txt for AI bot rules, verify SSR content, inspect structured data.
Category E: Entity & Brand Clarity (ENTITY)
| Check ID | Check | Principle | Method |
|---|---|---|---|
| ENTITY-01 | Product/brand name is consistently used | Entity recognition | Check name consistency across pages |
| ENTITY-02 | Clear product category declaration | AI classification | Check if content states "X is a [category]" explicitly |
| ENTITY-03 | Key features/differentiators stated clearly | AI comparison | Check for feature lists, unique value propositions |
| ENTITY-04 | Use case descriptions are specific | AI recommendation | Check for "best for [specific use case]" patterns |
| ENTITY-05 | Pricing/tier information is structured | AI recommendation | Check pricing page for clear, structured plans |
| ENTITY-06 | Integration/compatibility information present | AI recommendation | Check for "works with X" / integration pages |
| ENTITY-07 | Competitor differentiation is factual | AI comparison | Check comparison content for factual (not just marketing) claims |
| ENTITY-08 | Industry/vertical targeting is explicit | AI classification | Check if content targets specific industries/roles |
Browser validation: Navigate key pages and extract product positioning, feature lists, use cases, pricing structure. Check for entity-clear statements.
Category F: AI Citation Testing (TEST)
This category is unique to GEO — it tests actual AI visibility.
| Check ID | Check | Method |
|---|---|---|
| TEST-01 | Test target queries in Perplexity | Navigate to perplexity.ai, search target queries, check if your site is cited |
| TEST-02 | Test target queries in ChatGPT (if browsing available) | Search via ChatGPT, check citations |
| TEST-03 | Test target queries in Google (check AI Overview) | Google search, check if AI Overview cites your content |
| TEST-04 | Compare citation frequency vs competitors | Count citations for you vs top competitors across queries |
| TEST-05 | Analyze what content IS being cited (from competitors) | Study cited content format, structure, claims |
Browser validation: Use new_session to navigate to Perplexity and Google. Search target queries. Screenshot results. Check for citations to the user's domain. This provides real-world evidence of current AI visibility.
Important: TEST category results are the ground truth — they show whether your content is actually being cited, regardless of what the other categories suggest.
---
Phase 4: Report
Generate a structured report saved to shiplight/reports/geo-review-{date}.md:
# GEO Review Report
**Date:** {date}
**URL:** {url}
**Product type:** {description}
**Target AI queries tested:** {list}
## Overall GEO Score: {X}/10 | Confidence: {X}%
## Score Breakdown
| Category | Score | Findings |
|----------|-------|----------|
| Citation-Worthiness (CITE) | 5/10 | 2 high, 2 medium |
| Content Structure (STRUCT) | 6/10 | 1 high, 2 medium |
| Authority Signals (AUTH) | 7/10 | 1 medium |
| Technical Discoverability (TECH) | 4/10 | 1 critical, 2 high |
| Entity Clarity (ENTITY) | 5/10 | 2 high |
| AI Citation Testing (TEST) | 3/10 | Not cited in 4/5 target queries |
## AI Citation Status
| Target Query | Perplexity | Google AI Overview | Cited? | Competitor Cited? |
|-------------|------------|-------------------|--------|------------------|
| "best X for Y" | Not cited | Not in overview | ❌ | CompetitorA: ✅ |
| "how to do Z" | Cited (#3 source) | Cited | ✅ | CompetitorB: ✅ |
| ... | | | | |
## Citation Gap Analysis
What competitors' cited content has that yours doesn't:
- Specific performance benchmarks (CompetitorA cites "40% faster than...")
- Comparison tables (CompetitorB has detailed feature matrices)
- Direct answer paragraphs (CompetitorA leads sections with the conclusion)
## Findings
(structured findings with evidence and priority)Confidence Scoring
- 90-100%: Verified via live AI search — content is/isn't cited (TEST category)
- 70-89%: Strong structural evidence — content has/lacks citation-worthy patterns
- 50-69%: Heuristic assessment of content quality signals
- Below 50%: Don't report
---
Phase 5: Remediate
1. Fix guidance (example)
#### CITE-01: Landing page lacks specific, verifiable claims
**Impact:** AI systems skip vague marketing copy — your landing page is invisible to AI answers
**Current:** "We're the fastest platform for modern teams"
**Fix:** Add specific, citable claims:
- "Deploys complete in 47 seconds on average (based on 10,000 deployments in Q4 2025)"
- "Used by 2,300 companies including [notable names]"
- "Reduces CI/CD pipeline time by 62% compared to Jenkins (internal benchmark, Jan 2026)"
**Principle:** AI cites facts, not adjectives. Every claim should be verifiable.#### TECH-01: No llms.txt present
**Impact:** AI crawlers have no guidance on how to understand your site
**Fix:** Create /llms.txt at site root:
# [Your Product Name]
> One-sentence description of what your product does.
## Docs
- [Getting Started](/docs/getting-started): How to set up and configure [Product]
- [API Reference](/docs/api): Complete API documentation
- [Guides](/docs/guides): Step-by-step tutorials
## Key Pages
- [Pricing](/pricing): Plans and pricing
- [Changelog](/changelog): Recent updates and releases
- [About](/about): Company and team information
Also create /llms-full.txt with expanded content for deeper AI understanding.2. YAML regression tests
- name: tech-01-llms-txt-present
description: Verify llms.txt exists and is properly formatted
severity: high
standard: llms-txt-standard
steps:
- URL: /llms.txt
- VERIFY: The page loads successfully and contains structured information about the site
- description: Assert llms.txt is present and uses markdown headings
js: |
const content = await page.textContent('body');
if (!content || content.trim().length < 50) {
throw new Error('llms.txt is missing or too short');
}
if (!content.includes('#')) {
throw new Error('llms.txt should use markdown heading structure');
}
console.log(`llms.txt found (${content.length} chars)`);
- name: tech-06-ai-crawlers-allowed
description: Verify robots.txt allows AI search crawlers
severity: high
standard: AI-Discoverability
steps:
- URL: /robots.txt
- description: Assert robots.txt does not block AI crawlers
js: |
const content = await page.textContent('body');
const blockedBots = ['GPTBot', 'ClaudeBot', 'PerplexityBot', 'Google-Extended'];
const blocked = blockedBots.filter(bot => {
const pattern = new RegExp(`User-agent:\\s*${bot}[\\s\\S]*?Disallow:\\s*/`, 'i');
return pattern.test(content);
});
if (blocked.length > 0) {
throw new Error(`AI crawlers blocked in robots.txt: ${blocked.join(', ')}`);
}
console.log('All major AI crawlers are allowed');
- VERIFY: robots.txt does not block major AI search engine crawlers
- name: cite-01-specific-claims-present
description: Verify key pages contain specific, citable claims with data
severity: high
standard: GEO-Citation-Worthiness
steps:
- URL: /
- description: Assert the landing page has citable statistics
js: |
const text = await page.textContent('main') || await page.textContent('body');
// Check for specific numbers/statistics
const hasNumbers = /\d+[%xX]|\$[\d,.]+|\d{1,3}(,\d{3})+|\d+\s*(users|customers|companies|teams|downloads)/i.test(text);
if (!hasNumbers) {
throw new Error('Landing page lacks specific statistics or data points that AI can cite');
}
console.log('Found specific, citable claims with data');
- VERIFY: Landing page contains specific statistics, benchmarks, or verifiable data pointsSave all YAML tests to shiplight/tests/geo-review.test.yaml.
---
Depth Levels
- `--quick`: llms.txt check + robots.txt AI crawler check + landing page claim analysis. ~2 minutes.
- default: All content categories + 3 target query tests in Perplexity. ~10-15 minutes.
- `--thorough`: All categories + full AI citation testing across multiple engines + competitor citation analysis + content gap recommendations. ~25-40 minutes.
Tips
- The TEST category (live AI search testing) is the most valuable — it shows ground truth, not theory
- Perplexity is the best testing ground because it always shows citations
- llms.txt is emerging but increasingly adopted — it's low effort, high signal
- AI systems update their knowledge at different speeds — changes may take weeks to reflect in citations
- Focus on content that answers specific questions, not brand awareness content
- The #1 GEO principle: AI cites facts, not adjectives — replace every vague claim with a specific one
- Close session with
close_sessionand usegenerate_html_reportfor evidence
Performance Review
Measure and evaluate your application's performance against Google's Core Web Vitals thresholds and industry benchmarks. This review catches performance issues that are invisible during development but impact real users — bundle bloat, layout shifts, slow interactions, unoptimized images, and render-blocking resources.
When to use
Use this review when:
- Before launching or after major feature additions
- Page load feels slow but you're not sure why
- Preparing for high-traffic events
- After adding new dependencies or third-party scripts
- SEO rankings depend on performance scores
- Users report slowness or abandonment
Standards Referenced
- Google Core Web Vitals — LCP, INP, CLS (2024 thresholds)
- Google Lighthouse — Performance scoring methodology
- HTTP Archive — Web performance benchmarks (median, p75, p90)
- Web.dev Performance Guidelines — Best practices
- RAIL Model — Response, Animation, Idle, Load budgets
Phase Overview
Phase 1: EDUCATE → Performance impact on business and what we measure
Phase 2: SCOPE → Identify key pages, performance budget, baseline
Phase 3: ANALYZE → Browser-based performance measurement
Phase 4: REPORT → Findings with metrics, scores, and comparisons
Phase 5: REMEDIATE → Fix guidance + YAML regression tests---
Phase 1: Educate
Why this matters: A 1-second delay in page load reduces conversions by 7% (Akamai). Google uses Core Web Vitals as ranking signals since 2021. 53% of mobile visitors leave a page that takes >3 seconds to load (Google). Amazon found every 100ms of latency costs 1% of sales. Performance is a feature — and its absence is a bug.
This review measures real performance in a browser, not just static analysis. We capture actual load times, rendering behavior, and interaction responsiveness.
---
Phase 2: Scope
Gather context
1. Auto-detect from codebase:
- Build system (Webpack, Vite, Next.js, etc.)
- Bundle analysis setup (if any)
- Image optimization pipeline (sharp, next/image, etc.)
- Font loading strategy
- Code splitting configuration
- Service worker / caching strategy
- CDN configuration
2. Ask the user (one at a time):
- Target URL: Where is the app running? (production preferred for realistic measurements)
- Key pages: Which pages matter most for performance? (recommend: landing page, main feature page, data-heavy page)
- Performance budget: Any existing targets? (default: Core Web Vitals "Good" thresholds)
- Known concerns: Any pages that feel slow? (optional)
3. Define measurement plan:
- Pages to test (3-5 key pages)
- Conditions: desktop and mobile simulated (Moto G4 / Slow 4G)
- Metrics: Core Web Vitals + supplementary metrics
- Baseline: first run establishes baseline for comparison
---
Phase 3: Analyze
Open a browser session with new_session using record_evidence: true. For each page in scope, run all measurement categories.
Category A: Core Web Vitals (CWV)
| Check ID | Metric | Good | Needs Improvement | Poor | Method |
|---|---|---|---|---|---|
| CWV-01 | LCP (Largest Contentful Paint) | ≤2.5s | 2.5-4.0s | >4.0s | PerformanceObserver for LCP entries |
| CWV-02 | INP (Interaction to Next Paint) | ≤200ms | 200-500ms | >500ms | Click key interactive elements, measure delay |
| CWV-03 | CLS (Cumulative Layout Shift) | ≤0.1 | 0.1-0.25 | >0.25 | PerformanceObserver for layout-shift entries |
Browser validation: Navigate to each page and capture metrics via JavaScript:
// LCP
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lcp = entries[entries.length - 1];
console.log('LCP:', lcp.startTime);
}).observe({ type: 'largest-contentful-paint', buffered: true });
// CLS
let clsValue = 0;
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) clsValue += entry.value;
}
console.log('CLS:', clsValue);
}).observe({ type: 'layout-shift', buffered: true });Category B: Page Load Performance (LOAD)
| Check ID | Check | Threshold | Method |
|---|---|---|---|
| LOAD-01 | Time to First Byte (TTFB) | ≤800ms | performance.timing.responseStart - navigationStart |
| LOAD-02 | First Contentful Paint (FCP) | ≤1.8s | performance.getEntriesByName('first-contentful-paint') |
| LOAD-03 | DOM Content Loaded | ≤2.0s | performance.timing.domContentLoadedEventEnd |
| LOAD-04 | Total page weight | ≤3MB (mobile) / ≤5MB (desktop) | performance.getEntriesByType('resource') sum |
| LOAD-05 | Number of HTTP requests | ≤50 | Count resource entries |
| LOAD-06 | Time to Interactive (TTI) | ≤3.8s | Long task analysis |
| LOAD-07 | Total Blocking Time (TBT) | ≤200ms | Sum of long tasks (>50ms portions) |
| LOAD-08 | Speed Index | ≤3.4s | Visual progress analysis |
Browser validation: Use Performance API and performance.getEntries() to gather all metrics.
Category C: Resource Optimization (RES)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| RES-01 | Images use modern formats (WebP/AVIF) | Web.dev | Check image URLs and Content-Type |
| RES-02 | Images are appropriately sized (not oversized) | Web.dev | Compare display size vs natural size |
| RES-03 | Images use lazy loading (below-fold) | Web.dev | Check loading="lazy" on below-fold images |
| RES-04 | Images have explicit dimensions (width/height) | CLS prevention | Check for width/height attributes |
| RES-05 | CSS is not render-blocking (or is critical-inlined) | Web.dev | Check CSS loading strategy |
| RES-06 | JavaScript is deferred or async | Web.dev | Check script loading attributes |
| RES-07 | Fonts use font-display: swap or optional | Web.dev | Check @font-face declarations |
| RES-08 | Fonts are preloaded | Web.dev | Check for <link rel="preload" as="font"> |
| RES-09 | Gzip/Brotli compression enabled | HTTP best practice | Check Content-Encoding headers |
| RES-10 | HTTP/2 or HTTP/3 in use | HTTP best practice | Check protocol via Performance API |
| RES-11 | Effective caching headers | HTTP best practice | Check Cache-Control on static assets |
| RES-12 | No unused CSS/JS loaded | Bundle efficiency | Check coverage via Page.startJSCoverage/startCSSCoverage |
Browser validation: Use JavaScript to inspect all loaded resources, their types, sizes, and loading attributes. Use performance.getEntriesByType('resource') for detailed resource metrics.
Category D: Bundle Analysis (BUN)
| Check ID | Check | Threshold | Method |
|---|---|---|---|
| BUN-01 | Main JS bundle size | ≤250KB gzipped | Check transfer size of main bundle |
| BUN-02 | Total JS size | ≤500KB gzipped | Sum all JS transfer sizes |
| BUN-03 | Total CSS size | ≤100KB gzipped | Sum all CSS transfer sizes |
| BUN-04 | Code splitting implemented | Best practice | Check for multiple JS chunks |
| BUN-05 | No duplicate dependencies | Bundle efficiency | Analyze chunk contents for duplicates |
| BUN-06 | Tree shaking effective | Bundle efficiency | Check for known large unused exports |
| BUN-07 | Source maps not exposed in production | Security/Performance | Check for .map files accessibility |
| BUN-08 | Third-party JS budget | ≤30% of total JS | Calculate third-party vs first-party ratio |
Browser validation: Use Performance API to measure transfer sizes. Check for source map URLs. Analyze script domain origins.
Category E: Runtime Performance (RUN)
| Check ID | Check | Threshold | Method |
|---|---|---|---|
| RUN-01 | No long tasks during interaction | >50ms = long task | Use PerformanceObserver for long tasks |
| RUN-02 | Scroll performance is smooth | 60fps | Scroll page, measure frame drops |
| RUN-03 | Animation performance | 60fps | Trigger animations, measure jank |
| RUN-04 | Memory usage is stable (no leaks) | No growth pattern | Measure performance.memory over time |
| RUN-05 | No excessive DOM nodes | ≤1500 nodes | Count document.querySelectorAll('*').length |
| RUN-06 | No layout thrashing | 0 forced reflows | Monitor forced style recalculations |
| RUN-07 | Efficient event listeners | No excessive listeners | Check for scroll/resize listeners without throttle |
Browser validation: Navigate and interact with the app while measuring performance metrics via JavaScript.
---
Phase 4: Report
Generate a structured report saved to shiplight/reports/performance-review-{date}.md:
# Performance Review Report
**Date:** {date}
**URL:** {url}
**Pages tested:** {list}
**Conditions:** Desktop + Mobile (simulated Moto G4 / Slow 4G)
## Overall Score: {X}/10 | Confidence: {X}%
## Core Web Vitals Summary
| Metric | Desktop | Mobile | Status |
|--------|---------|--------|--------|
| LCP | 1.8s | 3.2s | ⚠️ Mobile needs work |
| INP | 95ms | 180ms | ✅ Good |
| CLS | 0.05 | 0.15 | ⚠️ Mobile needs work |
## Score Breakdown
| Category | Score | Findings |
|----------|-------|----------|
| Core Web Vitals (CWV) | 6/10 | 1 high, 1 medium |
| Page Load (LOAD) | 7/10 | 1 high |
| Resources (RES) | 5/10 | 2 high, 2 medium |
| Bundle (BUN) | 6/10 | 1 high, 1 medium |
| Runtime (RUN) | 8/10 | 1 medium |
## Resource Waterfall
(Top 10 slowest resources with load times)
## Bundle Breakdown
| Category | Size (gzipped) | Budget | Status |
|----------|---------------|--------|--------|
| First-party JS | 180KB | 250KB | ✅ |
| Third-party JS | 220KB | 150KB | ❌ Over budget |
| CSS | 45KB | 100KB | ✅ |
| Images | 1.2MB | 1.5MB | ✅ |
| Fonts | 85KB | 100KB | ✅ |
## Findings
(structured findings with metrics and evidence)Confidence Scoring
- 90-100%: Measured in browser with specific values (e.g., LCP: 3.2s)
- 70-89%: Derived from resource analysis (e.g., unoptimized images detected)
- 50-69%: Code-level pattern (e.g., no lazy loading attributes found)
- Below 50%: Don't report
---
Phase 5: Remediate
1. Fix guidance (example)
#### RES-01: Images not using modern formats
**Impact:** ~40% larger images than necessary, adds ~500KB to page weight
**Current:** 8 PNG images totaling 1.2MB
**Fix:** Convert to WebP with fallback:
- Use `<picture>` with WebP source and PNG fallback
- Or use Next.js `<Image>` / `sharp` for automatic format negotiation
- Expected savings: ~480KB (40% reduction)
**Priority files:**
- /images/hero.png (320KB → ~190KB as WebP)
- /images/features.png (280KB → ~165KB as WebP)2. YAML regression test
- name: cwv-01-lcp-under-threshold
description: Verify Largest Contentful Paint is under 2.5 seconds
severity: high
standard: Core-Web-Vitals-LCP
steps:
- description: Set up an LCP observer before navigation
js: |
// Set up LCP observer before navigation
await page.evaluateOnNewDocument(() => {
window.__lcp = 0;
new PerformanceObserver((list) => {
const entries = list.getEntries();
window.__lcp = entries[entries.length - 1].startTime;
}).observe({ type: 'largest-contentful-paint', buffered: true });
});
- URL: /
- WAIT_UNTIL: Page has fully loaded including all images and content
timeout_seconds: 30
- description: Assert Largest Contentful Paint is under 2.5s
js: |
const lcp = await page.evaluate(() => window.__lcp);
if (lcp > 2500) {
throw new Error(`LCP is ${lcp}ms, exceeds 2500ms threshold`);
}
console.log(`LCP: ${lcp}ms (threshold: 2500ms)`);
- VERIFY: Page loaded with Largest Contentful Paint under 2.5 secondsSave all YAML tests to shiplight/tests/performance-review.test.yaml.
---
Depth Levels
- `--quick`: Core Web Vitals only on the main page. ~2 minutes.
- default: All categories on key pages, desktop + mobile. ~8-12 minutes.
- `--thorough`: All categories + extended pages + multiple runs for statistical confidence + runtime profiling. ~20-30 minutes.
Tips
- Measure on production (or production-like build) — dev mode performance is misleading
- Run multiple times — performance measurements vary; look for patterns, not single data points
- Mobile simulation reveals issues that desktop hides — always test both
- Use
performance.getEntries()— it's the richest source of performance data in the browser - Focus on Core Web Vitals first — they're the metrics Google uses for ranking
- Close session with
close_sessionand usegenerate_html_reportfor evidence
Privacy Review
Evaluate how your application handles personal data — where it's collected, processed, stored, transmitted, and potentially leaked. This review catches privacy issues that code review alone misses: runtime data flows, third-party tracking, console/network leaks, and consent implementation gaps.
When to use
Use this review when:
- Your app collects any personal information (names, emails, addresses, etc.)
- Before launching in GDPR/CCPA jurisdictions
- Adding third-party analytics, tracking, or marketing tools
- After a data incident or privacy complaint
- Building features that handle sensitive data (health, financial, biometric)
- Integrating with third-party APIs that receive user data
Standards Referenced
- GDPR — EU General Data Protection Regulation (Articles 5, 6, 7, 12-22, 25, 32)
- CCPA/CPRA — California Consumer Privacy Act
- OWASP Privacy Risks Top 10
- NIST Privacy Framework
- ISO 27701 — Privacy Information Management
- ePrivacy Directive — Cookie consent requirements
Phase Overview
Phase 1: EDUCATE → Privacy principles and what we check
Phase 2: SCOPE → Map data flows, PII types, third parties
Phase 3: ANALYZE → Browser-based validation of privacy practices
Phase 4: REPORT → Findings with evidence and confidence scores
Phase 5: REMEDIATE → Fix guidance + YAML regression tests---
Phase 1: Educate
Why this matters: GDPR fines reached €2.1B in 2023. CCPA gives consumers the right to sue for data breaches ($100-$750 per consumer per incident). Beyond compliance, privacy violations erode user trust — 79% of consumers say they'd stop engaging with a brand after a privacy breach. Many privacy issues are invisible in code review but obvious in runtime behavior.
This review focuses on observable runtime privacy behavior — what actually happens in the browser when users interact with your app.
---
Phase 2: Scope
Gather context
1. Auto-detect from codebase:
- Forms that collect user input (registration, profile, payment, contact)
- Analytics/tracking scripts (Google Analytics, Mixpanel, Segment, Hotjar, etc.)
- Cookie-setting code and cookie consent mechanisms
- Logging statements that might include PII
- API calls that transmit user data
- Third-party SDKs and their data sharing behavior
- Privacy policy and terms of service pages
2. Ask the user (one at a time):
- Target URL: Where is the app running?
- Data types: What personal data does your app collect? (auto-detected, confirm)
- Jurisdictions: Where are your users? (determines GDPR/CCPA/other applicability)
- Third parties: What analytics/tracking/marketing tools do you use? (auto-detected, confirm)
- Known concerns: Any specific privacy areas you're worried about? (optional)
3. Build data flow map:
- PII entry points (forms, URL params, imports)
- PII processing (client-side or server-side)
- PII storage (cookies, localStorage, server DB)
- PII transmission (API calls, third-party scripts)
- PII display (profile pages, admin panels, logs)
---
Phase 3: Analyze
Open a browser session with new_session using record_evidence: true. Run all applicable check categories.
Category A: Data Collection & Consent (CON)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| CON-01 | Cookie consent banner shown before setting non-essential cookies | ePrivacy / GDPR Art.7 | Load page, check if tracking cookies exist before consent |
| CON-02 | No tracking scripts fire before consent | ePrivacy / GDPR | Monitor network requests on fresh page load (no consent given) |
| CON-03 | Consent is granular (not just "accept all") | GDPR Art.7 | Check consent UI for category-level options |
| CON-04 | Rejecting consent actually prevents tracking | GDPR Art.7 | Reject all, verify no tracking cookies/requests |
| CON-05 | Consent preference is persisted and respected | GDPR Art.7 | Set preference, reload page, verify it's remembered |
| CON-06 | Consent can be withdrawn (modify/revoke) | GDPR Art.7(3) | Find mechanism to change consent after initial choice |
| CON-07 | Privacy policy is accessible and linked | GDPR Art.12-14 | Check for privacy policy link in footer/consent banner |
| CON-08 | Data collection is proportionate (no unnecessary fields) | GDPR Art.5(1)(c) | Review forms for fields not needed for stated purpose |
Browser validation: Load page in fresh session (no cookies). Use get_browser_console_logs and monitor network via JavaScript. Check cookies before and after consent interaction. Use act to interact with consent banner.
Category B: PII Leakage Detection (LEAK)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| LEAK-01 | No PII in URL parameters | OWASP Privacy #1 | Check URLs after form submissions, navigation |
| LEAK-02 | No PII in browser console logs | OWASP Privacy #4 | Check get_browser_console_logs for email, names, IDs |
| LEAK-03 | No PII in localStorage/sessionStorage | Data minimization | Inspect client storage for personal data |
| LEAK-04 | No PII in page source/comments | Information leak | Check HTML comments, hidden fields |
| LEAK-05 | No PII in error messages | OWASP Privacy #7 | Trigger errors, check for user data in messages |
| LEAK-06 | No PII in Referer headers | OWASP Privacy | Check Referrer-Policy, inspect outbound requests |
| LEAK-07 | No PII in meta tags or Open Graph | Information leak | Check <meta> for user-specific data on shared pages |
| LEAK-08 | No PII in cached responses (browser cache) | Data minimization | Check Cache-Control headers on pages with PII |
| LEAK-09 | No PII leaked to third-party scripts | GDPR Art.28 | Monitor data sent to analytics/tracking endpoints |
| LEAK-10 | Autocomplete appropriate on sensitive fields | Usability/Privacy | Check autocomplete attribute on password, CC fields |
Browser validation: Navigate through user flows. After each action, check URLs, console logs, storage, and network requests for PII patterns (email regex, phone patterns, SSN patterns, etc.). Use JavaScript to inspect performance.getEntries() for request URLs.
Category C: Third-Party Tracking Inventory (TRACK)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| TRACK-01 | Inventory all third-party scripts | GDPR Art.30 | List all external script sources and their domains |
| TRACK-02 | All third-party scripts are documented | Transparency | Cross-reference with privacy policy |
| TRACK-03 | No unknown/unexpected tracking pixels | Privacy | Check for 1x1 images, beacon requests |
| TRACK-04 | Third-party cookies inventory | ePrivacy | List all cookies by domain |
| TRACK-05 | No fingerprinting scripts | Privacy | Check for canvas fingerprint, WebGL, AudioContext probing |
| TRACK-06 | Data sent to third parties is proportionate | GDPR Art.5(1)(c) | Inspect payloads to analytics endpoints |
| TRACK-07 | Tracking respects Do-Not-Track header | Best practice | Set DNT header, check if tracking still fires |
Browser validation: Load page with fresh session. Use JavaScript to enumerate all <script> sources, all cookie domains, all network requests to external domains. Check for fingerprinting API usage (Canvas, WebGL, AudioContext).
Category D: Data Storage & Retention (STOR)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| STOR-01 | Sensitive data encrypted in transit (HTTPS) | GDPR Art.32 | Check all resource URLs use HTTPS |
| STOR-02 | Session data has appropriate expiry | Data minimization | Check cookie/token expiration times |
| STOR-03 | No excessive data in cookies | Data minimization | Check cookie sizes and contents |
| STOR-04 | Client-side storage is minimal | Data minimization | Audit localStorage/sessionStorage contents |
| STOR-05 | Sensitive form data not persisted in history | Privacy | Check if sensitive forms use POST, not GET |
| STOR-06 | Browser back button doesn't show sensitive data after logout | Session management | Logout, press back, check for cached sensitive content |
Browser validation: Inspect all cookies (name, value, domain, expiry, flags). Check localStorage/sessionStorage. Test logout + back button behavior.
Category E: User Rights Implementation (RIGHTS)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| RIGHTS-01 | Users can access their data (data export) | GDPR Art.15 / CCPA | Find and test data export feature |
| RIGHTS-02 | Users can delete their account/data | GDPR Art.17 | Find and verify account deletion flow |
| RIGHTS-03 | Users can update their personal information | GDPR Art.16 | Test profile edit functionality |
| RIGHTS-04 | Opt-out mechanism for data selling (CCPA) | CCPA §1798.120 | Check for "Do Not Sell" link |
| RIGHTS-05 | Account deletion is complete (not just deactivation) | GDPR Art.17 | Delete account, verify data is removed (check profile URL) |
Browser validation: Navigate to account settings, test data export, profile editing, and account deletion flows. Verify each right is accessible and functional.
---
Phase 4: Report
Generate a structured report saved to shiplight/reports/privacy-review-{date}.md:
# Privacy Review Report
**Date:** {date}
**URL:** {url}
**PII types handled:** {list}
**Jurisdictions:** {GDPR, CCPA, etc.}
**Third parties detected:** {count and list}
## Overall Score: {X}/10 | Confidence: {X}%
## Score Breakdown
| Category | Score | Findings |
|----------|-------|----------|
| Consent (CON) | 5/10 | 1 critical, 2 high |
| PII Leakage (LEAK) | 7/10 | 1 high, 1 medium |
| Tracking Inventory (TRACK) | 4/10 | 2 high, 1 medium |
| Data Storage (STOR) | 8/10 | 1 medium |
| User Rights (RIGHTS) | 6/10 | 1 high, 1 medium |
## Data Flow Map
(visual representation of PII flows through the application)
## Third-Party Tracking Inventory
| Domain | Type | Cookies Set | Data Sent | Consent Required |
|--------|------|-------------|-----------|-----------------|
| google-analytics.com | Analytics | _ga, _gid | Page URL, user agent | Yes |
| ... | | | | |
## Findings
(structured findings with evidence, severity, confidence)Confidence Scoring
- 90-100%: Browser-validated — observed PII in console, URL, or network request
- 70-89%: Strong evidence from storage/header inspection
- 50-69%: Code-level pattern match, may not manifest at runtime
- Below 50%: Don't report
---
Phase 5: Remediate
1. Fix guidance (example)
#### LEAK-01: Email address in URL parameter after form submit
**Risk:** PII in URL is logged by servers, proxies, browser history, and analytics
**File:** src/pages/search.tsx:34
**Current:** `router.push(`/results?email=${email}`)`
**Fix:** Use POST request or session state
- `router.push('/results')` with email in request body or session
- Add `Referrer-Policy: no-referrer` header as defense-in-depth2. YAML regression test
- name: leak-01-no-pii-in-urls
description: Verify email addresses are not exposed in URL parameters
severity: high
standard: OWASP-Privacy-1
steps:
- URL: /search
- intent: Enter email in search form
action: fill
locator: "getByLabel('Email')"
value: "test@example.com"
- intent: Submit the search form
action: click
locator: "getByRole('button', { name: 'Search' })"
- WAIT_UNTIL: Search results are displayed
timeout_seconds: 15
- description: Assert no email address appears in the URL
js: |
const url = page.url();
if (/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/.test(url)) {
throw new Error(`PII found in URL: ${url}`);
}
- VERIFY: No email addresses appear in the browser URLSave all YAML tests to shiplight/tests/privacy-review.test.yaml.
---
Tips
- Use a fresh browser session (no stored cookies) to test consent behavior accurately
- PII patterns to search for: email (
@), phone (\d{3}[-.]?\d{3}[-.]?\d{4}), SSN, credit card numbers, names from test accounts - Third-party scripts often load more scripts — check for cascade loading
get_browser_console_logsoften reveals PII that developers left in debug logging- Test with consent rejected AND accepted — both paths matter
- Close session with
close_sessionand usegenerate_html_reportfor evidence
Shared Review Conventions
Conventions every domain review follows. Each references/<domain>.md defines the domain-specific checks; this file defines the cross-cutting rules they share, so the router can merge their output into one consistent report.
The five-phase model
Every domain review runs the same shape:
Phase 1: EDUCATE → why this domain matters + what we check
Phase 2: SCOPE → auto-detect from the codebase, confirm with the user, map surface
Phase 3: ANALYZE → browser-based checks against the domain's categories
Phase 4: REPORT → findings with evidence, scores, and confidence
Phase 5: REMEDIATE → fix guidance + YAML regression testsBrowser evidence
Domain analysis runs against a live target through the Shiplight MCP. Open the session with new_session using record_evidence: true, and close it with close_session. Use generate_html_report for an auditable artifact. Findings that claim runtime behavior need browser evidence, not code-reading alone.
Scoring and confidence
- Score: each review reports an overall
{X}/10plus a per-category
breakdown. The router's unified report carries each domain's score.
- Confidence (per finding):
- 90–100% — browser-validated; the issue was observed at runtime.
- 70–89% — strong evidence from inspection (headers, storage, DOM).
- 50–69% — code-level pattern; may not manifest at runtime.
- Below 50% — do not report; too speculative.
Each domain tailors the examples for these bands; the bands themselves are uniform.
Severity
Order findings by severity: CRITICAL → HIGH → MEDIUM → LOW / INFO. The router surfaces the top findings across all domains by this ordering.
Output paths
- Per-domain report:
shiplight/reports/<domain>-review-{date}.md - YAML regression tests:
shiplight/tests/<domain>-review.test.yaml - Unified report (router):
shiplight/reports/review-{date}.md
Regression tests accumulate in shiplight/tests/ so a review's findings become durable checks, not one-off observations.
Resilience Review
Evaluate how your application behaves when things go wrong — network failures, API errors, slow connections, missing data, and edge cases. Most apps are built for the happy path; this review systematically tests the unhappy paths that real users encounter.
When to use
Use this review when:
- Before launching a user-facing feature
- After adding new API integrations or data sources
- When reliability is critical (healthcare, finance, e-commerce checkout)
- After production incidents caused by unhandled errors
- When moving from prototype to production quality
Standards Referenced
- Google SRE Principles — Error budgets, graceful degradation
- Netflix Chaos Engineering Principles — Verify steady state, inject real-world failures
- OWASP Error Handling — Secure and user-friendly error responses
- Nielsen Norman Group — Error message usability heuristics
Phase Overview
Phase 1: EDUCATE → Why resilience matters and what we test
Phase 2: SCOPE → Map failure points, dependencies, critical flows
Phase 3: ANALYZE → Browser-based fault injection and edge case testing
Phase 4: REPORT → Findings with evidence and user impact assessment
Phase 5: REMEDIATE → Fix guidance + YAML regression tests---
Phase 1: Educate
Why this matters: Users don't experience your app in ideal conditions. 53% of mobile visits are abandoned if a page takes >3 seconds. Error pages with no guidance increase support tickets 5x. A blank screen is the worst possible failure mode — it tells the user nothing and offers no recovery path. Resilient apps maintain trust even when backend systems fail.
This review simulates real-world failure conditions in the browser and evaluates how your UI responds.
---
Phase 2: Scope
Gather context
1. Auto-detect from codebase:
- API calls and their endpoints
- Error boundary components (React ErrorBoundary, Vue errorHandler)
- Loading state implementations (spinners, skeletons, suspense)
- Empty state components
- Retry logic / error recovery patterns
- Offline support (service workers, cache strategies)
- Third-party service dependencies
2. Ask the user (one at a time):
- Target URL: Where is the app running?
- Critical user flows: Which flows must never show a blank screen? (auto-detect from routes)
- Key API dependencies: Which APIs does the frontend depend on? (auto-detected)
- Known fragile areas: Any pages/features that break frequently? (optional)
3. Map failure points:
- API endpoints the frontend calls (and what happens if each fails)
- Third-party dependencies (CDN, auth provider, analytics, maps, payment)
- Data-dependent UI (what shows when data is empty, missing, or malformed)
- User input edge cases (long text, special characters, empty submissions)
---
Phase 3: Analyze
Open a browser session with new_session using record_evidence: true. Run all applicable check categories.
Category A: Error Handling (ERR)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| ERR-01 | API errors show user-friendly message (not blank screen) | UX best practice | Mock API to return 500, check UI response |
| ERR-02 | Network timeout shows appropriate state | UX best practice | Mock network delay (30s), check UI |
| ERR-03 | 404 page exists and is helpful | UX best practice | Navigate to non-existent route |
| ERR-04 | JavaScript errors don't crash the page | Error boundaries | Inject JS error, check if page recovers |
| ERR-05 | Error messages are actionable | NN/g heuristics | Check error messages for: what happened, why, what to do |
| ERR-06 | Errors don't expose technical details | OWASP | Check error messages for stack traces, SQL, internal paths |
| ERR-07 | Form validation errors are clear and positioned | UX best practice | Submit invalid forms, check error placement and text |
| ERR-08 | Error states allow retry without page refresh | UX best practice | After error, check for retry button or recovery action |
| ERR-09 | Concurrent error handling (multiple simultaneous failures) | Resilience | Mock multiple API failures, check UI doesn't cascade |
| ERR-10 | Error logging doesn't expose PII | OWASP / Privacy | Check get_browser_console_logs during errors |
Browser validation: Use description: + js: statements to intercept network requests via page.route() to simulate failures. Check UI state after each failure. Use get_browser_console_logs for JavaScript errors.
// Example: Mock API 500 error
await page.route('**/api/**', route => {
route.fulfill({ status: 500, body: JSON.stringify({ error: 'Internal Server Error' }) });
});Category B: Graceful Degradation (DEG)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| DEG-01 | Page works with JavaScript disabled (basic content) | Progressive enhancement | Disable JS, check if content is accessible |
| DEG-02 | Page works on slow connection (3G simulation) | Performance | Throttle to Slow 3G, check load behavior |
| DEG-03 | Non-critical features degrade without breaking critical ones | Graceful degradation | Disable third-party scripts, check core functionality |
| DEG-04 | Offline state is handled (if applicable) | PWA best practice | Go offline, check UI state and messaging |
| DEG-05 | Third-party service failure doesn't block page load | Resilience | Block third-party domains, check page loads |
| DEG-06 | Image loading failure shows fallback | UX best practice | Block image URLs, check for alt text/placeholder |
| DEG-07 | Font loading failure doesn't hide text | FOUT handling | Block font URLs, check text remains visible |
| DEG-08 | Feature detection over browser sniffing | Progressive enhancement | Check code for navigator.userAgent vs feature detection |
Browser validation: Use page.route() to block specific resources. Use CDP to simulate network conditions. Disable JavaScript via browser settings. Verify each degradation scenario.
Category C: Empty & Edge States (EDGE)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| EDGE-01 | Empty data state shows helpful message | UX best practice | Navigate to pages with no data, check display |
| EDGE-02 | Pagination handles zero results | UX best practice | Search for nonexistent term, check pagination |
| EDGE-03 | Long text doesn't break layout | Defensive CSS | Enter very long strings (500+ chars), check overflow |
| EDGE-04 | Special characters in input don't break UI | Input handling | Enter <script>, "'&<>, emoji, Unicode |
| EDGE-05 | Large data sets don't freeze UI | Performance | Load pages with maximum data, check responsiveness |
| EDGE-06 | Rapid user actions don't cause duplicate submissions | State management | Double-click submit buttons, rapid nav |
| EDGE-07 | Back/forward navigation maintains state | History management | Fill form, navigate away, come back |
| EDGE-08 | Refresh preserves expected state | State persistence | Refresh during multi-step flow, check state |
| EDGE-09 | Concurrent tab/session behavior | Session management | Open same page in two tabs, perform actions |
| EDGE-10 | Maximum file upload size handled | Input validation | Upload oversized file, check error message |
Browser validation: Navigate to pages and test each edge case. Use act to interact with forms, submit empty/extreme data. Use JavaScript to check for UI overflow, frozen states.
Category D: API Contract & Data Handling (API)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| API-01 | UI handles all HTTP error codes gracefully | API contract | Mock 400, 401, 403, 404, 422, 429, 500, 503 |
| API-02 | UI handles null/undefined fields without crashing | Defensive coding | Mock API response with null fields |
| API-03 | UI handles empty arrays/objects | Defensive coding | Mock API response with empty collections |
| API-04 | UI handles unexpected data types | Defensive coding | Mock API response with wrong types |
| API-05 | Loading states shown during API calls | UX best practice | Add 2s delay to API, verify loading indicator |
| API-06 | Race conditions handled (stale responses) | State management | Trigger rapid sequential requests, verify latest wins |
| API-07 | Rate limiting (429) handled with user feedback | API contract | Mock 429 response, check UI feedback |
| API-08 | Authentication expiry handled mid-session | Session management | Mock 401 during session, check redirect to login |
Browser validation: Use page.route() to mock each response scenario. Verify UI state after each mock.
Category E: Recovery & User Communication (REC)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| REC-01 | Retry mechanisms exist for transient failures | Resilience | Mock intermittent failure, check auto-retry |
| REC-02 | User can manually retry after failure | UX best practice | After error, verify retry action available |
| REC-03 | Progress is not lost on errors | UX best practice | Fill long form, trigger error, check data persists |
| REC-04 | User is informed of degraded functionality | Communication | When features fail, check for degradation notice |
| REC-05 | Recovery actions are clear and accessible | NN/g heuristics | After each error type, evaluate recovery UX |
| REC-06 | Status indicators for background operations | UX best practice | Start async operation, verify progress feedback |
Browser validation: Use fault injection then verify recovery paths.
---
Phase 4: Report
Generate a structured report saved to shiplight/reports/resilience-review-{date}.md:
# Resilience Review Report
**Date:** {date}
**URL:** {url}
**Critical flows tested:** {list}
**API dependencies tested:** {count}
**Failure scenarios simulated:** {count}
## Overall Score: {X}/10 | Confidence: {X}%
## Score Breakdown
| Category | Score | Findings |
|----------|-------|----------|
| Error Handling (ERR) | 5/10 | 2 critical, 1 high |
| Graceful Degradation (DEG) | 6/10 | 1 high, 2 medium |
| Empty & Edge States (EDGE) | 4/10 | 1 critical, 3 high |
| API Contract (API) | 7/10 | 1 high, 1 medium |
| Recovery (REC) | 3/10 | 2 high, 1 medium |
## Failure Matrix
| Failure Scenario | Expected Behavior | Actual Behavior | Status |
|-----------------|-------------------|-----------------|--------|
| API returns 500 | Error message + retry | Blank screen | FAIL |
| Network timeout | Loading → timeout message | Infinite spinner | FAIL |
| Empty data set | "No results" message | Blank page | FAIL |
| ... | | | |
## Findings
(structured findings with evidence, screenshots of failure states)Confidence Scoring
- 90-100%: Fault injected and failure behavior verified in browser
- 70-89%: Code analysis shows missing error handling, not validated at runtime
- 50-69%: Pattern-based assessment (e.g., no error boundary detected)
- Below 50%: Don't report
---
Phase 5: Remediate
1. Fix guidance (example)
#### ERR-01: API error shows blank screen instead of error message
**Impact:** Users see empty page, think app is broken, leave
**File:** src/pages/Dashboard.tsx:45
**Current:** `const data = await fetch('/api/data').then(r => r.json())`
**Problem:** No error handling — fetch throws on network error, .json() throws on non-JSON response
**Fix:**
- Wrap in try/catch
- Add error state: `const [error, setError] = useState(null)`
- Render error UI with retry button
- Add React Error Boundary as fallback2. YAML regression test
- name: err-01-api-error-shows-message
description: Verify API failure shows user-friendly error message instead of blank screen
severity: critical
standard: UX-Error-Handling
steps:
- description: Mock the data API to return a 500 error
js: |
await page.route('**/api/data**', route => {
route.fulfill({
status: 500,
contentType: 'application/json',
body: JSON.stringify({ error: 'Internal Server Error' })
});
});
- URL: /dashboard
- WAIT_UNTIL: Page has finished attempting to load data
timeout_seconds: 15
- VERIFY: An error message is visible explaining that data could not be loaded
- VERIFY: A retry button or recovery action is available to the user
- VERIFY: The page is NOT blank — navigation and header are still visibleSave all YAML tests to shiplight/tests/resilience-review.test.yaml.
---
Tips
- Use
page.route()indescription: + js:statements — it's the primary tool for fault injection - Test the most critical user flows first (checkout, signup, core feature)
- A blank screen is always a CRITICAL finding — it's the worst failure mode
- Check
get_browser_console_logsfor uncaught promise rejections — they indicate missing error handling - Edge case testing (EDGE category) often reveals the most bugs per minute spent
- Close session with
close_sessionand usegenerate_html_reportfor evidence
Security Review
Evaluate your application's security posture against industry standards and validate findings through browser-based penetration testing. This review covers the attack surface that static analysis tools miss — runtime behavior, header configuration, authentication flows, and client-side vulnerabilities.
When to use
Use this review when:
- Before launching a new application or feature
- After adding authentication or authorization changes
- When handling sensitive data (user credentials, payment info, PII)
- Preparing for a security audit
- After a security incident to check for similar issues
- Reviewing third-party integrations
Standards Referenced
- OWASP Top 10 (2021) — Top web application security risks
- OWASP ASVS v4.0 — Application Security Verification Standard
- OWASP Session Management Cheat Sheet
- NIST 800-63B — Digital Identity Guidelines (authentication)
- CWE/SANS Top 25 — Most Dangerous Software Weaknesses
- Mozilla Observatory — HTTP security header best practices
Phase Overview
Phase 1: EDUCATE → Security context and what we check
Phase 2: SCOPE → Identify attack surface, auth mechanisms, data flows
Phase 3: ANALYZE → Automated checks + browser-based penetration testing
Phase 4: REPORT → Findings with evidence, CVE references, confidence scores
Phase 5: REMEDIATE → Fix guidance + YAML regression tests---
Phase 1: Educate
Why this matters: The average cost of a data breach is $4.45M (IBM 2023). 83% of web applications have at least one critical vulnerability. Many security issues are only detectable at runtime — misconfigured headers, insecure token storage, broken access controls — which is exactly what browser-based testing catches.
This review checks your app against objective security criteria with browser-based validation. Every finding references a specific standard (OWASP, CWE, NIST).
---
Phase 2: Scope
Gather context
1. Auto-detect from codebase:
- Authentication mechanism (JWT, sessions, OAuth, API keys)
- Framework security features in use (CSRF tokens, CORS config, CSP)
- Dependencies with known vulnerabilities (
npm audit/pip audit) - API routes and endpoints
- Environment variable handling
- File upload capabilities
- Third-party scripts and CDN usage
2. Ask the user (one at a time):
- Target URL: Where is the app running?
- Auth mechanism: How do users log in? (auto-detected, confirm)
- Test credentials: Do you have test accounts I can use? (needed for authenticated testing)
- Sensitive data: What sensitive data does the app handle? (PII, payments, health records)
- Known concerns: Any specific areas you're worried about? (optional)
3. Map the attack surface:
- List all user input points (forms, URL params, file uploads, WebSocket messages)
- List all API endpoints with their auth requirements
- List all third-party integrations
- Identify data flow: where does sensitive data enter, process, store, and exit?
---
Phase 3: Analyze
Open a browser session with new_session using record_evidence: true. Run all applicable check categories.
Category A: HTTP Security Headers (HDR)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| HDR-01 | Content-Security-Policy header present and restrictive | OWASP A05 | Inspect response headers |
| HDR-02 | Strict-Transport-Security (HSTS) with long max-age | OWASP Transport | Check header presence and value |
| HDR-03 | X-Content-Type-Options: nosniff | Mozilla Observatory | Check header |
| HDR-04 | X-Frame-Options or CSP frame-ancestors | OWASP Clickjacking | Check header |
| HDR-05 | Referrer-Policy set appropriately | Privacy/Security | Check header value |
| HDR-06 | Permissions-Policy restricts sensitive APIs | Browser security | Check camera, microphone, geolocation policies |
| HDR-07 | No Server/X-Powered-By version disclosure | Information leak | Check for version strings in headers |
| HDR-08 | Cache-Control for sensitive pages | OWASP Session | Check no-store for authenticated content |
| HDR-09 | CORS not overly permissive | OWASP A05 | Check Access-Control-Allow-Origin |
| HDR-10 | No mixed content (HTTP resources on HTTPS page) | Transport security | Inspect all resource URLs |
Browser validation: Use JavaScript via act to inspect document.querySelector('meta[http-equiv]') and fetch response headers via a same-origin request. Use get_browser_console_logs to check for mixed content warnings.
Category B: Authentication & Session Management (AUTH)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| AUTH-01 | Tokens not stored in localStorage | OWASP ASVS 3.3.2 | Check localStorage/sessionStorage for tokens |
| AUTH-02 | Session cookies have HttpOnly flag | OWASP Session | Inspect Set-Cookie headers |
| AUTH-03 | Session cookies have Secure flag | OWASP Session | Inspect Set-Cookie headers |
| AUTH-04 | Session cookies have SameSite attribute | OWASP CSRF | Inspect Set-Cookie headers |
| AUTH-05 | Session expires after idle timeout | OWASP ASVS 3.3.1 | Wait and verify session invalidation |
| AUTH-06 | Logout invalidates server-side session | OWASP ASVS 3.3.1 | Logout, replay old token, check response |
| AUTH-07 | Password reset tokens are single-use | OWASP Auth | Use reset link twice, verify second fails |
| AUTH-08 | No credentials in URL parameters | OWASP Transport | Check URL for tokens/passwords |
| AUTH-09 | Brute force protection on login | OWASP Auth | Attempt multiple failed logins, check for lockout/rate-limit |
| AUTH-10 | CSRF protection on state-changing requests | OWASP A01 | Submit forms without CSRF token |
| AUTH-11 | JWT signature verified (if applicable) | OWASP Auth | Send modified JWT, check rejection |
| AUTH-12 | OAuth state parameter used (if applicable) | OWASP Auth | Check OAuth flow for state param |
Browser validation: Log in via act, inspect cookies with JavaScript (document.cookie — HttpOnly cookies won't appear, which is correct). Check localStorage. Perform logout, replay requests. Attempt brute force (5 wrong passwords). Modify JWT tokens and test.
Category C: Input Validation & Injection (INJ)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| INJ-01 | XSS: reflected input in page | OWASP A03 / CWE-79 | Submit <script>alert(1)</script> in all inputs, check if rendered |
| INJ-02 | XSS: stored input from database | OWASP A03 / CWE-79 | Submit script via form, check if rendered on subsequent page loads |
| INJ-03 | SQL injection in form inputs | OWASP A03 / CWE-89 | Submit ' OR '1'='1 patterns, check for errors |
| INJ-04 | Open redirect via URL parameters | CWE-601 | Test redirect params with external URLs |
| INJ-05 | Path traversal in file operations | CWE-22 | Test ../../etc/passwd in file-related params |
| INJ-06 | Command injection in input fields | CWE-78 | Test ; ls or ` |
| INJ-07 | HTML injection in user content | CWE-79 | Submit HTML tags, check if rendered |
| INJ-08 | URL scheme validation (javascript:) | CWE-79 | Test javascript:alert(1) in URL inputs |
| INJ-09 | File upload validation | OWASP A04 | Upload files with wrong extensions, oversized files, executable content |
| INJ-10 | API input validation | OWASP A03 | Send malformed JSON, missing fields, wrong types to API endpoints |
Browser validation: Use act to fill form fields with test payloads. Capture page state after submission. Check for script execution, error messages, unexpected behavior. Use get_browser_console_logs for JavaScript errors that indicate injection vectors.
Important: These are non-destructive test payloads for detection only. Do not attempt actual exploitation. Alert-based XSS tests use alert(1) which is harmless.
Category D: Access Control (AC)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| AC-01 | Authenticated pages return 401/403 without auth | OWASP A01 | Access protected URLs without authentication |
| AC-02 | No IDOR (Insecure Direct Object Reference) | OWASP A01 / CWE-639 | Change resource IDs in URLs, check for unauthorized access |
| AC-03 | API endpoints enforce authorization | OWASP A01 | Call API endpoints with wrong/missing auth |
| AC-04 | Admin pages are not accessible to regular users | OWASP A01 | Navigate to admin routes with regular user session |
| AC-05 | No sensitive data in client-side source | Information leak | Check JavaScript bundles for API keys, secrets |
| AC-06 | Directory listing disabled | Information leak | Access directory URLs (e.g., /api/, /static/) |
| AC-07 | Debug endpoints not exposed in production | OWASP A05 | Check common debug paths (/debug, /trace, /graphql playground) |
| AC-08 | Error messages don't leak internal details | OWASP A05 | Trigger errors, check for stack traces, DB details |
Browser validation: Navigate to protected pages without auth. Try accessing resources belonging to other users. Check JavaScript source for hardcoded secrets using act with JavaScript to scan script contents.
Category E: Client-Side Security (CLI)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| CLI-01 | No sensitive data in client-side storage | OWASP Storage | Inspect localStorage, sessionStorage, IndexedDB |
| CLI-02 | Subresource Integrity (SRI) on CDN resources | Supply chain | Check integrity attribute on external scripts/styles |
| CLI-03 | Third-party scripts inventory | Supply chain | List all external script sources |
| CLI-04 | No eval() or innerHTML with user input | CWE-79 | Scan JavaScript for dangerous patterns |
| CLI-05 | Service worker scope is restricted | Client security | Check SW registration scope |
| CLI-06 | WebSocket connections use WSS | Transport | Check WS connection URLs |
| CLI-07 | No sensitive data in console logs | Information leak | Check get_browser_console_logs output |
| CLI-08 | Clickjacking protection works | OWASP Clickjacking | Test embedding page in iframe |
Browser validation: Use JavaScript via act to enumerate localStorage keys, check script tags for SRI, list all network requests to external domains. Use get_browser_console_logs to check for leaked data.
Category F: Dependency & Supply Chain (DEP)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| DEP-01 | No known vulnerable dependencies | OWASP A06 / CWE-1035 | Run npm audit / pip audit |
| DEP-02 | Lock file exists and is committed | Supply chain | Check for package-lock.json / yarn.lock / pnpm-lock.yaml |
| DEP-03 | No unnecessary dependencies | Attack surface | Check for unused packages |
| DEP-04 | CDN resources use SRI | Supply chain | Check integrity attributes (same as CLI-02) |
| DEP-05 | No typosquatting risk in dependencies | Supply chain | Check package names against known packages |
Validation: Run dependency audit commands. Cross-reference with codebase scan from Phase 2.
---
Phase 4: Report
Generate a structured report saved to shiplight/reports/security-review-{date}.md:
# Security Review Report
**Date:** {date}
**URL:** {url}
**Auth mechanism:** {type}
**Attack surface:** {summary}
## Overall Score: {X}/10 | Confidence: {X}%
## Score Breakdown
| Category | Score | Findings |
|----------|-------|----------|
| HTTP Headers (HDR) | 6/10 | 1 critical, 2 high |
| Auth & Sessions (AUTH) | 4/10 | 2 critical, 1 high |
| Input Validation (INJ) | 7/10 | 1 high, 2 medium |
| Access Control (AC) | 8/10 | 1 medium |
| Client-Side (CLI) | 5/10 | 1 critical, 1 high |
| Dependencies (DEP) | 9/10 | 1 low |
## Findings
### CRITICAL
#### AUTH-01: JWT stored in localStorage — XSS leads to full account takeover
- **Standard:** OWASP ASVS 3.3.2 / CWE-922
- **Finding:** Access token stored in `localStorage` under key `auth_token`, accessible to any XSS payload
- **Evidence:** [screenshot of Application > Storage showing JWT]
- **Attack scenario:** Any XSS vulnerability (even via third-party script) can exfiltrate all user tokens
- **CVSS estimate:** 8.1 (High)
- **Confidence:** 95%
...Confidence Scoring
- 90-100%: Exploited and verified in browser (e.g., XSS payload executed, unauthorized access confirmed)
- 70-89%: Strong evidence from inspection (e.g., missing header confirmed, insecure cookie flags observed)
- 50-69%: Code-level evidence, not fully validated at runtime
- Below 50%: Don't report — too speculative
---
Phase 5: Remediate
For each finding, provide:
1. Fix guidance
#### AUTH-01: JWT stored in localStorage
**Risk:** Any XSS → full account takeover
**File:** src/lib/auth.ts:47
**Current:** `localStorage.setItem('auth_token', jwt)`
**Fix:** Move to HttpOnly cookie set by the server
- Server: `Set-Cookie: token=<jwt>; HttpOnly; Secure; SameSite=Strict; Path=/`
- Client: Remove all localStorage token operations
- API calls: Cookies sent automatically (remove Authorization header)
**Migration steps:**
1. Add cookie-setting endpoint on server
2. Update API middleware to read from cookie
3. Remove client-side token storage
4. Update CORS to allow credentials2. YAML regression test
- name: auth-01-no-tokens-in-localstorage
description: Verify authentication tokens are not stored in localStorage
severity: critical
standard: OWASP-ASVS-3.3.2
steps:
- URL: /login
- intent: Enter test username
action: fill
locator: "getByLabel('Email')"
value: "test@example.com"
- intent: Enter test password
action: fill
locator: "getByLabel('Password')"
value: "testpass123"
- intent: Click login button
action: click
locator: "getByRole('button', { name: 'Sign in' })"
- WAIT_UNTIL: User is logged in and dashboard is visible
timeout_seconds: 15
- description: Assert no auth tokens are stored in localStorage
js: |
const keys = Object.keys(localStorage);
const tokenKeys = keys.filter(k =>
/token|jwt|auth|session|access/i.test(k)
);
if (tokenKeys.length > 0) {
throw new Error(
`Auth tokens found in localStorage: ${tokenKeys.join(', ')}`
);
}
- VERIFY: No authentication tokens are stored in browser localStorageSave all YAML tests to shiplight/tests/security-review.test.yaml.
---
Penetration Test Depth Levels
- `--quick`: Headers (HDR) + Cookie flags (AUTH-02/03/04) + localStorage check (AUTH-01) + dependency audit (DEP-01). ~2 minutes.
- default: All categories, standard payloads. ~10 minutes.
- `--thorough`: All categories + extended injection payloads + IDOR enumeration + brute force testing + full third-party script analysis. ~20-30 minutes.
Tips
- Always use test credentials, never production credentials
- XSS test payloads are non-destructive (
alert(1)) — safe for staging environments - For authenticated testing, save the session with
save_storage_stateafter login - Run
npm auditbefore the browser-based review to catch known CVEs early - Use
get_browser_console_logs— many security issues produce console warnings - Close the session with
close_sessionand usegenerate_html_reportfor evidence
SEO Review
Evaluate your application's search engine optimization and discoverability. This review catches SEO issues that are invisible during normal development — missing meta tags, broken structured data, poor crawlability, missing sitemaps, and social sharing problems. Many SPAs ship with zero SEO consideration.
When to use
Use this review when:
- Before launching a public-facing website or application
- After redesigning or migrating a website
- When organic traffic is a growth channel
- After switching to an SPA framework (React, Vue, Angular)
- When social sharing (Open Graph) is important
- Setting up content marketing pages
Standards Referenced
- Google Search Central — SEO best practices and guidelines
- Schema.org — Structured data vocabulary
- Open Graph Protocol — Social sharing meta tags
- Twitter Card — Twitter sharing markup
- W3C Semantic HTML — Accessibility and SEO semantics
- Web.dev SEO Guidelines — Google's SEO recommendations
Phase Overview
Phase 1: EDUCATE → Why SEO matters and what we check
Phase 2: SCOPE → Identify key pages, content types, SEO goals
Phase 3: ANALYZE → Browser-based SEO validation
Phase 4: REPORT → Findings with impact assessment and priority
Phase 5: REMEDIATE → Fix guidance + YAML regression tests---
Phase 1: Educate
Why this matters: 53% of all website traffic comes from organic search (BrightEdge). The first Google result gets 27.6% of all clicks; position 10 gets 2.4% (Backlinko). SPAs often render blank HTML to crawlers, making millions of pages invisible to search. Proper SEO doesn't require tricks — it requires making your content discoverable and understandable by search engines.
This review checks the technical SEO foundation — the things that must be correct before content strategy matters.
---
Phase 2: Scope
Gather context
1. Auto-detect from codebase:
- Framework and rendering strategy (SSR, SSG, CSR, ISR)
- Meta tag management (react-helmet, next/head, vue-meta, etc.)
- Sitemap generation
- robots.txt configuration
- Structured data (JSON-LD, microdata)
- i18n/hreflang setup
- Canonical URL handling
- Route structure and page types
2. Ask the user (one at a time):
- Target URL: Where is the app running? (production preferred for realistic crawling)
- Key pages: Which pages are most important for search? (homepage, product pages, blog posts, landing pages)
- Target keywords: Any primary keywords you want to rank for? (optional, for content evaluation)
- Social sharing important?: Is Open Graph / Twitter Cards needed? (default: yes for public sites)
- Multi-language?: Does the site serve multiple languages? (auto-detected)
3. Identify page types:
- Homepage
- Content pages (blog, docs, about)
- Product/listing pages
- Dynamic pages (search results, user profiles)
- Utility pages (login, 404, terms)
---
Phase 3: Analyze
Open a browser session with new_session using record_evidence: true. For each key page, run all check categories.
Category A: Meta Tags & Head Elements (META)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| META-01 | Unique, descriptive <title> (50-60 chars) | Google guidelines | Extract <title>, check length and uniqueness |
| META-02 | Meta description present (120-160 chars) | Google guidelines | Check <meta name="description"> |
| META-03 | Canonical URL set correctly | Google guidelines | Check <link rel="canonical"> |
| META-04 | Viewport meta tag present | Mobile SEO | Check <meta name="viewport"> |
| META-05 | Charset declared | HTML standard | Check <meta charset> |
| META-06 | No duplicate meta tags | SEO best practice | Check for duplicate titles, descriptions |
| META-07 | Favicon present | Branding/SEO | Check <link rel="icon"> |
| META-08 | Language declared | SEO/a11y | Check <html lang=""> |
| META-09 | No meta robots noindex on important pages | Indexing | Check <meta name="robots"> |
| META-10 | Hreflang tags for multi-language (if applicable) | International SEO | Check <link rel="alternate" hreflang=""> |
Browser validation: Use inspect_page to read the DOM. Extract all <head> elements via JavaScript.
Category B: Structured Data (SCHEMA)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| SCHEMA-01 | JSON-LD structured data present | Schema.org | Check for <script type="application/ld+json"> |
| SCHEMA-02 | Schema type matches page content | Schema.org | Validate type (Organization, Product, Article, etc.) |
| SCHEMA-03 | Required properties present | Schema.org | Validate against type requirements |
| SCHEMA-04 | JSON-LD is valid JSON | Schema.org | Parse and validate JSON |
| SCHEMA-05 | No deprecated schema properties | Schema.org | Check for deprecated fields |
| SCHEMA-06 | Breadcrumb structured data | Schema.org | Check for BreadcrumbList on interior pages |
| SCHEMA-07 | FAQ structured data (if applicable) | Schema.org | Check for FAQPage on FAQ sections |
| SCHEMA-08 | Review/Rating structured data (if applicable) | Schema.org | Check for AggregateRating |
Browser validation: Extract JSON-LD scripts via JavaScript. Parse and validate structure. Compare page content against schema claims.
Category C: Open Graph & Social Sharing (OG)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| OG-01 | og:title present and meaningful | Open Graph | Check <meta property="og:title"> |
| OG-02 | og:description present | Open Graph | Check <meta property="og:description"> |
| OG-03 | og:image present and accessible | Open Graph | Check <meta property="og:image">, verify URL loads |
| OG-04 | og:image dimensions adequate (1200x630 recommended) | Open Graph | Check image size |
| OG-05 | og:url matches canonical | Open Graph | Compare og:url with canonical |
| OG-06 | og:type set correctly | Open Graph | Check og:type value |
| OG-07 | Twitter card meta tags present | Twitter Cards | Check twitter:card, twitter:title, etc. |
| OG-08 | Social sharing preview looks correct | UX | Construct preview from OG tags |
Browser validation: Extract all OG and Twitter meta tags. Verify og:image URL is accessible. Construct a preview representation.
Category D: Crawlability & Indexing (CRAWL)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| CRAWL-01 | robots.txt exists and is valid | Google guidelines | Fetch /robots.txt |
| CRAWL-02 | Sitemap.xml exists and is valid | Google guidelines | Fetch /sitemap.xml, validate format |
| CRAWL-03 | Sitemap referenced in robots.txt | Best practice | Check robots.txt for Sitemap directive |
| CRAWL-04 | Important pages are in sitemap | SEO | Cross-reference key pages with sitemap URLs |
| CRAWL-05 | No broken internal links | Crawlability | Check all internal links on key pages |
| CRAWL-06 | No redirect chains (>2 hops) | Crawl efficiency | Follow redirects, count hops |
| CRAWL-07 | Clean URL structure (no excessive params) | SEO | Check URL patterns for cleanliness |
| CRAWL-08 | 404 page returns correct HTTP status | SEO | Navigate to non-existent URL, check status |
| CRAWL-09 | No orphan pages (accessible from navigation) | Crawlability | Verify key pages linked from homepage/nav |
| CRAWL-10 | SSR/SSG content visible without JavaScript | SPA SEO | Disable JS, check if content renders |
| CRAWL-11 | Page load time for crawlers | Crawl budget | Measure server response time |
Browser validation: Navigate to robots.txt, sitemap.xml. Follow internal links. Disable JavaScript to test server-rendered content. Check HTTP status codes.
Category E: Semantic HTML & Content (SEM)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| SEM-01 | Single <h1> per page | SEO best practice | Count h1 elements |
| SEM-02 | Heading hierarchy is logical (h1→h2→h3) | SEO/a11y | Check heading sequence |
| SEM-03 | Images have descriptive alt text | SEO/a11y | Check alt attributes for descriptiveness |
| SEM-04 | Internal links use descriptive anchor text | SEO | Check for "click here" or bare URLs as links |
| SEM-05 | Semantic HTML elements used (nav, main, article, section) | SEO | Check for semantic landmarks |
| SEM-06 | Content-to-HTML ratio is reasonable | SEO | Calculate text content vs HTML markup |
| SEM-07 | No duplicate content across pages | SEO | Compare key content sections across pages |
| SEM-08 | URLs are human-readable | SEO | Check for descriptive slugs vs IDs/hashes |
Browser validation: Extract headings, links, images, and semantic elements via JavaScript. Analyze content structure.
Category F: Technical SEO (TECH)
| Check ID | Check | Standard | Method |
|---|---|---|---|
| TECH-01 | HTTPS everywhere | Google ranking signal | Check protocol |
| TECH-02 | HTTP → HTTPS redirect works | SEO | Test HTTP URL redirect |
| TECH-03 | www → non-www (or vice versa) redirect consistent | SEO | Test both variants |
| TECH-04 | Mobile-friendly (responsive) | Google mobile-first | Check viewport, responsive behavior |
| TECH-05 | Core Web Vitals pass "Good" thresholds | Google ranking signal | Measure LCP, INP, CLS |
| TECH-06 | No render-blocking resources | Page speed | Check script/style loading |
| TECH-07 | Proper 301 redirects for moved content | SEO | Check known old URLs if applicable |
| TECH-08 | International targeting correct (if multi-region) | International SEO | Check hreflang, geo-targeting |
Browser validation: Test redirects, measure performance metrics, check mobile rendering.
---
Phase 4: Report
Generate a structured report saved to shiplight/reports/seo-review-{date}.md:
# SEO Review Report
**Date:** {date}
**URL:** {url}
**Pages reviewed:** {list}
**Rendering:** {SSR/SSG/CSR/ISR}
## Overall Score: {X}/10 | Confidence: {X}%
## Score Breakdown
| Category | Score | Findings |
|----------|-------|----------|
| Meta Tags (META) | 7/10 | 1 high, 2 medium |
| Structured Data (SCHEMA) | 4/10 | 1 critical, 1 high |
| Social Sharing (OG) | 6/10 | 2 high |
| Crawlability (CRAWL) | 5/10 | 1 critical, 1 high |
| Semantic HTML (SEM) | 8/10 | 1 medium |
| Technical SEO (TECH) | 7/10 | 1 high |
## Page-by-Page Summary
| Page | Title | Description | OG Image | Schema | H1 | Score |
|------|-------|-------------|----------|--------|----|-------|
| / | ✅ | ✅ | ❌ missing | ❌ none | ✅ | 6/10 |
| /blog | ✅ | ⚠️ too short | ✅ | ✅ Article | ✅ | 8/10 |
## Findings
(structured findings with evidence and impact)Confidence Scoring
- 90-100%: Verified in browser — tag present/absent, URL accessible/broken
- 70-89%: Content analysis suggests issue (e.g., thin content, generic alt text)
- 50-69%: Best practice recommendation without clear violation
- Below 50%: Don't report
---
Phase 5: Remediate
1. Fix guidance (example)
#### CRAWL-10: Content not visible without JavaScript
**Impact:** Search engines may not index your content (especially Google Discover, Bing, social crawlers)
**Current:** Client-side rendered React app, empty HTML shell
**Fix:** Implement SSR or SSG:
- Next.js: Use `getServerSideProps` or `getStaticProps`
- Nuxt: Default SSR mode
- Gatsby: Static generation
- Or: Add prerendering service (prerender.io, rendertron)
**Quick win:** Ensure critical content is in initial HTML response2. YAML regression test
- name: meta-01-title-present
description: Verify each key page has a unique, properly-sized title tag
severity: high
standard: Google-SEO-Guidelines
steps:
- URL: /
- description: Assert the page title is present and 20-60 characters
js: |
const title = await page.title();
if (!title || title.trim() === '') {
throw new Error('Page has no title');
}
if (title.length < 20) {
throw new Error(`Title too short (${title.length} chars): "${title}"`);
}
if (title.length > 60) {
throw new Error(`Title too long (${title.length} chars): "${title}"`);
}
console.log(`Title OK (${title.length} chars): "${title}"`);
- VERIFY: Page has a descriptive title between 20 and 60 charactersSave all YAML tests to shiplight/tests/seo-review.test.yaml.
---
Depth Levels
- `--quick`: Meta tags + canonical + robots.txt on homepage only. ~2 minutes.
- default: All categories on key pages. ~8-12 minutes.
- `--thorough`: All categories + full site crawl + all page types + content analysis. ~20-30 minutes.
Tips
- Test with JavaScript disabled to see what search engines see (especially for SPAs)
- Use
inspect_pageDOM output to extract<head>content efficiently - Check sitemap.xml manually — auto-generated sitemaps often include pages that shouldn't be indexed
- OG image must be an absolute URL — relative URLs don't work for social sharing
- For SPA SEO, the critical question is: "Does the initial HTML contain the content?"
- Close session with
close_sessionand usegenerate_html_reportfor evidence
Related skills
How it compares
Use review when the needed audit domain is unclear or multiple areas matter; invoke a single domain skill directly when the request is already scoped (e.g., security-only).
FAQ
What domains does the review skill cover?
The review skill orchestrates eight domains: security, privacy, compliance, design, resilience, performance, SEO, and GEO. Each domain loads from references/<domain>.md only when triage or a targeted /review <domain> command selects it.
How do review skill modes differ?
The review skill defaults to triage: context questions, a recommended plan, then selected domains. /review --all runs every applicable domain; /review security (or seo, privacy, etc.) jumps straight in with optional --quick or --thorough depth.