Site review
14 opinionated skills for running a healthcare AI startup as a solo founder — daily briefings, PMF intelligence, sales coaching, conference pipelines, and content creation as slash commands
npx -y skills add jp-solumhealth/jpstack --skill site-reviewAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Comprehensive website SEO and conversion audit with built-in fact-checking. Technical SEO, tactical SEO, intake/lead form assessment, and CRO analysis. Use when asked to "review a site", "SEO audit", "check a website", "conversion audit", "site review", "website analysis", or "intake assessment".
SKILL.md
16.3 KB, as published. Nobody here has run it
Site Review — SEO & Conversion Audit with Fact-Checking
Run a comprehensive website review covering technical SEO, tactical SEO, intake/conversion assessment, and CRO opportunities. Every finding is internally verified before reporting.
Critical Rule: Verify Everything
NEVER report a finding without verifying it through at least two methods. The #1 failure mode of site reviews is false findings. Common traps:
| False Finding | Reality | How to Verify |
|---|---|---|
| "No chat widget" | Chat loads async via third-party script | Check all <script> sources for chat providers |
| "Phone number mismatch" | Dynamic number insertion (CallRail, etc.) | Check for call tracking scripts, inspect JS |
| "No structured data" | Schema in <script type="application/ld+json"> | Search full HTML for ld+json |
| "Form only has X fields" | Fields render via JS or are below fold | Use snapshot -i to find ALL interactive elements |
| "No analytics" | Tag manager loads analytics async | Check for GTM, Segment, or other tag managers |
| "Missing meta tags" | Tags set dynamically via JS framework | Run js "document.querySelector('meta[name=description]')?.content" |
Workflow
Phase 0: Setup & Initial Scan
B=~/.claude/skills/gstack/browse/dist/browse
# Navigate and wait for full load
PATH="$HOME/.bun/bin:$PATH" $B goto <url>
PATH="$HOME/.bun/bin:$PATH" $B wait "body"
# Capture baseline data (run all)
PATH="$HOME/.bun/bin:$PATH" $B text # Full page text
PATH="$HOME/.bun/bin:$PATH" $B snapshot -i # All interactive elements
PATH="$HOME/.bun/bin:$PATH" $B links # All links
PATH="$HOME/.bun/bin:$PATH" $B perf # Performance timings
PATH="$HOME/.bun/bin:$PATH" $B screenshot /tmp/site-review.png # Visual capture
Phase 1: Technical SEO Audit
Check each item. For every finding, note the verification method used.
1A. Page Speed & Core Web Vitals
# Performance timing
PATH="$HOME/.bun/bin:$PATH" $B perf
# Check resource loading
PATH="$HOME/.bun/bin:$PATH" $B js "performance.getEntriesByType('resource').length"
PATH="$HOME/.bun/bin:$PATH" $B js "performance.getEntriesByType('resource').filter(r => r.duration > 500).map(r => r.name + ' (' + Math.round(r.duration) + 'ms)').join('\n')"
# Check image optimization
PATH="$HOME/.bun/bin:$PATH" $B js "document.querySelectorAll('img').length"
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('img')].filter(i => !i.loading).map(i => i.src).join('\n')"
Check:
- Page load time (DOMContentLoaded, Load)
- Number of HTTP requests
- Large/slow resources (>500ms)
- Images without lazy loading
- Render-blocking resources
1B. Meta Tags & SEO Essentials
# Meta tags (verify via JS, not just HTML source)
PATH="$HOME/.bun/bin:$PATH" $B js "document.title"
PATH="$HOME/.bun/bin:$PATH" $B js "document.querySelector('meta[name=\"description\"]')?.content || 'MISSING'"
PATH="$HOME/.bun/bin:$PATH" $B js "document.querySelector('link[rel=\"canonical\"]')?.href || 'MISSING'"
PATH="$HOME/.bun/bin:$PATH" $B js "document.querySelector('meta[name=\"robots\"]')?.content || 'NOT SET'"
# Open Graph
PATH="$HOME/.bun/bin:$PATH" $B js "document.querySelector('meta[property=\"og:title\"]')?.content || 'MISSING'"
PATH="$HOME/.bun/bin:$PATH" $B js "document.querySelector('meta[property=\"og:description\"]')?.content || 'MISSING'"
PATH="$HOME/.bun/bin:$PATH" $B js "document.querySelector('meta[property=\"og:image\"]')?.content || 'MISSING'"
Check:
- Title tag (present, <60 chars, includes primary keyword)
- Meta description (present, <160 chars, compelling)
- Canonical URL (present, correct)
- Robots meta (not accidentally blocking)
- Open Graph tags (title, description, image)
- Twitter Card tags
1C. Structured Data
# Check ALL script tags for schema (MUST do this, not just check one spot)
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('script[type=\"application/ld+json\"]')].map(s => JSON.parse(s.textContent)['@type'] || 'unknown').join(', ') || 'NO SCHEMA FOUND'"
# Get full schema content
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('script[type=\"application/ld+json\"]')].map(s => s.textContent).join('\n---\n')"
Check:
- Organization schema
- LocalBusiness schema (if applicable)
- Service/Product schema
- FAQ schema (if FAQ exists on page)
- BreadcrumbList schema
- Review/Rating schema (if applicable)
1D. Crawlability & Indexing
# Check robots.txt
PATH="$HOME/.bun/bin:$PATH" $B goto <base-url>/robots.txt
PATH="$HOME/.bun/bin:$PATH" $B text
# Check sitemap
PATH="$HOME/.bun/bin:$PATH" $B goto <base-url>/sitemap.xml
PATH="$HOME/.bun/bin:$PATH" $B text
# Return to main page
PATH="$HOME/.bun/bin:$PATH" $B goto <url>
Check:
- robots.txt exists and is valid
- sitemap.xml exists and is valid
- No critical pages blocked by robots.txt
- Sitemap includes all important pages
1E. Mobile & Responsive
# Check viewport meta
PATH="$HOME/.bun/bin:$PATH" $B js "document.querySelector('meta[name=\"viewport\"]')?.content || 'MISSING'"
# Mobile screenshot
PATH="$HOME/.bun/bin:$PATH" $B viewport 375x812
PATH="$HOME/.bun/bin:$PATH" $B screenshot /tmp/site-review-mobile.png
# Check for horizontal scroll issues
PATH="$HOME/.bun/bin:$PATH" $B js "document.documentElement.scrollWidth > document.documentElement.clientWidth"
# Reset viewport
PATH="$HOME/.bun/bin:$PATH" $B viewport 1440x900
Check:
- Viewport meta tag present
- No horizontal scroll on mobile
- Text readable without zooming
- Touch targets adequate size (48x48px min)
- Images scale properly
1F. Security & Performance
# Check HTTPS, cookies, headers
PATH="$HOME/.bun/bin:$PATH" $B js "location.protocol"
PATH="$HOME/.bun/bin:$PATH" $B js "document.cookie"
# Check for mixed content
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('[src]')].filter(el => el.src.startsWith('http://')).map(el => el.tagName + ': ' + el.src).join('\n') || 'No mixed content'"
Check:
- HTTPS enabled
- No mixed content warnings
- HTTP → HTTPS redirect works
Phase 2: Tactical SEO Audit
2A. Heading Structure
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('h1,h2,h3,h4,h5,h6')].map(h => h.tagName + ': ' + h.textContent.trim().substring(0,80)).join('\n')"
Check:
- Single H1 tag
- H1 includes primary keyword
- Logical heading hierarchy (no skipped levels)
- Headings are descriptive, not generic
2B. Content Quality
# Word count
PATH="$HOME/.bun/bin:$PATH" $B js "document.body.innerText.split(/\\s+/).length"
# Check for thin content areas
PATH="$HOME/.bun/bin:$PATH" $B text
Check:
- Sufficient word count for topic (500+ for service pages, 1000+ for articles)
- Primary keyword used naturally in body text
- No keyword stuffing
- Content addresses user intent
- E-E-A-T signals present (credentials, experience, expertise)
2C. Internal Linking
# Get all internal links
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('a[href]')].filter(a => a.href.includes(location.hostname)).map(a => a.textContent.trim().substring(0,40) + ' → ' + a.pathname).join('\n')"
# Check for broken anchor text
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('a[href]')].filter(a => !a.textContent.trim() && !a.querySelector('img')).map(a => a.href).join('\n') || 'All links have text'"
Check:
- Internal links to key pages
- Descriptive anchor text (not "click here")
- No orphan pages (pages with no internal links pointing to them)
- Navigation is clear and complete
2D. Local SEO (if applicable)
# Check for address/location info
PATH="$HOME/.bun/bin:$PATH" $B js "document.body.innerText.match(/\\d{5}(-\\d{4})?/g) || 'No zip codes found'"
# Check for phone numbers
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('a[href^=\"tel:\"]')].map(a => a.href).join(', ') || 'No tel: links'"
Check:
- NAP consistency (Name, Address, Phone)
- LocalBusiness schema
- Google Business Profile link
- Service area pages (if multi-location)
Phase 3: Third-Party Tools & Scripts Inventory
This phase prevents false findings. Before reporting on chat, analytics, call tracking, or any third-party tool, inventory everything that's loaded.
# Get ALL external scripts
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('script[src]')].map(s => s.src).join('\n')"
# Get ALL iframes
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('iframe')].map(f => f.src || f.id || 'anonymous iframe').join('\n')"
# Check for common tools by global variables
PATH="$HOME/.bun/bin:$PATH" $B js "({gtm: typeof google_tag_manager !== 'undefined', ga: typeof gtag !== 'undefined' || typeof ga !== 'undefined', fbq: typeof fbq !== 'undefined', hotjar: typeof hj !== 'undefined', hubspot: typeof _hsq !== 'undefined', intercom: typeof Intercom !== 'undefined', drift: typeof drift !== 'undefined', crisp: typeof $crisp !== 'undefined', zendesk: typeof zE !== 'undefined', callrail: !!document.querySelector('script[src*=\"callrail\"],script[src*=\"calltrk\"]'), leadtrap: !!document.querySelector('script[src*=\"leadtrap\"]'), vwo: typeof _vwo_code !== 'undefined'})"
Identify and document:
- Analytics (GA4, GTM, Segment, Mixpanel, etc.)
- Chat widgets (Intercom, Drift, Crisp, Zendesk, custom)
- Call tracking (CallRail, CallTrackingMetrics, etc.)
- A/B testing (VWO, Optimizely, Google Optimize)
- CRM integrations (HubSpot, Salesforce)
- Marketing pixels (Facebook, LinkedIn, Google Ads)
- Form tools (Typeform, Jotform, embedded forms)
- CMS platform (WordPress, Webflow, Squarespace, custom)
Phase 4: Intake & Conversion Assessment
4A. Lead Capture Forms
# Find ALL forms and their fields
PATH="$HOME/.bun/bin:$PATH" $B snapshot -i
# Detailed form field inventory
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('form')].map((f,i) => 'Form ' + i + ':\\n' + [...f.querySelectorAll('input,select,textarea')].map(el => ' ' + (el.name||el.id||el.type) + ' (' + el.type + ')' + (el.required ? ' [required]' : '')).join('\\n')).join('\\n\\n') || 'No forms found'"
Check:
- Form exists above the fold
- Form fields are appropriate (not too many, not too few)
- Required fields marked
- Form has clear CTA button text (not just "Submit")
- Form has privacy/consent text
- Mobile form usability
- Form validation present
- Thank you page / confirmation exists
4B. CTAs & Conversion Points
# Find all buttons and CTAs
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('button, a.btn, a.button, [class*=\"cta\"], [class*=\"btn\"]')].map(el => el.textContent.trim().substring(0,50) + ' → ' + (el.href || 'button')).join('\\n')"
# Check phone links
PATH="$HOME/.bun/bin:$PATH" $B js "[...document.querySelectorAll('a[href^=\"tel:\"]')].map(a => a.textContent.trim() + ' → ' + a.href).join('\\n') || 'No phone links'"
Check:
- Primary CTA is clear and prominent
- CTA text is action-oriented (not "Submit" or "Click Here")
- Phone number is clickable (tel: link)
- Multiple conversion paths (form, phone, chat)
- CTAs visible on mobile without scrolling
- Sticky header/footer with CTA on mobile
4C. Trust Signals
PATH="$HOME/.bun/bin:$PATH" $B js "document.body.innerText"
Look for in page text:
- Credentials/certifications
- Insurance accepted list
- Testimonials/reviews
- Awards/recognition
- Years of experience
- Team/provider bios
- HIPAA compliance mention
- Accreditation badges
4D. Chat & Real-Time Support
# Already identified in Phase 3 — cross-reference here
# Verify the chat widget actually loads and is functional
PATH="$HOME/.bun/bin:$PATH" $B js "document.querySelectorAll('[class*=\"chat\"], [id*=\"chat\"], [class*=\"widget\"], [data-chat]').length"
PATH="$HOME/.bun/bin:$PATH" $B screenshot /tmp/site-review-chat.png
Check:
- Chat widget present and visible
- Chat is accessible on mobile
- Chat doesn't block important content
Phase 5: Healthcare-Specific Checks (if applicable)
- HIPAA compliance mentioned
- Insurance/payer information clear
- Service area clearly defined
- Intake process explained
- Emergency/crisis resources provided (if behavioral health)
- Provider credentials displayed
- Telehealth vs in-person options clear
- Appointment scheduling available
Phase 6: Internal Fact-Check & Validation
This is the most important phase. Run it BEFORE delivering the report.
For every finding from Phases 1-5, apply this validation:
Validation Matrix
| Finding Type | Verification Method 1 | Verification Method 2 |
|---|---|---|
| "Missing element" | snapshot -i interactive scan | js DOM query |
| "No third-party tool" | Script source inventory | Global variable check |
| "Broken/missing link" | goto the URL directly | Check response status |
| "No schema/markup" | js query for ld+json | HTML source search |
| "Phone mismatch" | Check for call tracking scripts | Compare with footer |
| "Form issue" | snapshot -i for all fields | js form field query |
| "Missing analytics" | Check for tag managers | Check global variables |
| "Content issue" | Re-read full text | Check multiple pages |
Fact-Check Process
For each finding in your draft report:
- State the finding clearly
- Method 1: How you initially found it
- Method 2: How you verified it (must be different from Method 1)
- Confidence: HIGH (verified 2+ ways) / MEDIUM (verified 1 way, plausible) / LOW (single signal, could be wrong)
- If confidence is LOW: Run additional checks or mark as "Needs manual verification"
Rules:
- NEVER report LOW confidence findings as definitive problems
- ALWAYS note when something loads asynchronously (chat, forms, tracking)
- ALWAYS check for tag managers before claiming "no analytics"
- ALWAYS check for call tracking before flagging phone number mismatches
- ALWAYS use
snapshot -ibefore claiming forms are missing fields - If uncertain, say "Could not confirm" rather than making a false claim
Phase 7: Deliver the Report
============================================
SITE REVIEW — [URL]
[Date]
============================================
TOOLS & PLATFORM DETECTED
---------------------------
CMS: [platform]
Analytics: [tools]
Chat: [tool or None]
Call Tracking: [tool or None]
A/B Testing: [tool or None]
CRM: [tool or None]
Other: [list]
TECHNICAL SEO
--------------
Score: X/10
[Findings with confidence level for each]
TACTICAL SEO
--------------
Score: X/10
[Findings with confidence level for each]
INTAKE & CONVERSION
---------------------
Score: X/10
[Findings with confidence level for each]
TRUST & CREDIBILITY
---------------------
Score: X/10
[Findings with confidence level for each]
TOP PRIORITIES (ranked by impact)
===================================
1. [Highest impact fix] — effort: [S/M/L]
2. [Second priority] — effort: [S/M/L]
3. [Third priority] — effort: [S/M/L]
...
ITEMS NEEDING MANUAL VERIFICATION
------------------------------------
[Any findings that could not be fully verified automatically]
Error Handling
- If browse tool fails: note which checks couldn't be performed
- If a page requires authentication: note and skip those checks
- If JavaScript is disabled or fails: fall back to HTML source analysis
- Never skip the fact-check phase, even if browse has issues
- If the site blocks automated access: note it and provide recommendations based on what was accessible
Tone
- Objective and data-driven
- No speculation presented as fact
- Confidence levels on every finding
- Actionable recommendations with effort estimates
- Honest about limitations of automated review