Automated Lighthouse Audits with Claude Code

2025-01-05

#performance#lighthouse#claude-code#web-dev#tooling

I got tired of running Lighthouse, squinting at the JSON output, and manually figuring out what actually matters. So I set up a slash command in Claude Code that runs the audit and tells me what to fix. Took about 5 minutes to set up, saves me 20+ minutes every time I check performance.

The Manual Way

If you've never used Lighthouse from the command line:

npx lighthouse https://yoursite.com \
  --output=json \
  --output-path=/tmp/lighthouse-report.json \
  --chrome-flags="--headless" \
  --only-categories=performance

This dumps a ~500KB JSON blob. You can open it in Chrome DevTools or pipe it through jq to extract what you care about:

cat /tmp/lighthouse-report.json | jq '{
  score: (.categories.performance.score * 100),
  lcp: .audits["largest-contentful-paint"].displayValue,
  cls: .audits["cumulative-layout-shift"].displayValue,
  tbt: .audits["total-blocking-time"].displayValue
}'

Output:

{
  "score": 55,
  "lcp": "58.1 s",
  "cls": "0",
  "tbt": "0 ms"
}

That 58 second LCP is... not great. But now I have to dig through the full report to figure out why, and that's where I usually give up and go do something else.

The Slash Command

Create a file at .claude/commands/analyze-website-performance.md:

# Website Performance Analysis

Analyze the performance of `$ARGUMENTS` using Google Lighthouse.

## Steps

1. **Run Lighthouse audit**:

   ```bash
   npx lighthouse $ARGUMENTS --output=json --output-path=/tmp/lighthouse-report.json --chrome-flags="--headless" --only-categories=performance
   ```

2. **Read the report** from `/tmp/lighthouse-report.json`

3. **Analyze and summarize**:
   - Current performance score
   - Each failing audit with its impact
   - Specific fixes for each issue
   - Estimated score improvement from each fix

## Output Format

### Performance Score: X/100

### Critical Issues (blocking 95+ score)

For each issue:

- **What**: The specific problem
- **Impact**: How many points this costs
- **Fix**: Exact steps to resolve

## Constraints

**Do not recommend changes that would:**

- Alter the DOM structure significantly
- Change the visual design
- Remove features or content

**Focus only on:**

- Asset optimization (compression, formats, sizing)
- Loading strategies (defer, async, preload, lazy loading)
- Caching and delivery
- Code efficiency (tree-shaking, code splitting)

Now run it:

claude
> /analyze-website-performance https://samratjha.com

What Comes Back

Instead of a wall of JSON, you get something like:

## Performance Score: 55/100

### Critical Issues

### 1. Massive Image Files - Est. Savings: 15,654 KiB (~15.3 MB)

| Image | Current Size | Displayed At | Savings |
|-------|-------------|--------------|---------|
| ParallaxImageGallery.png | 8.87 MB | 431×230 px | 8.86 MB |
| bird-radio.png | 2.30 MB | 450×230 px | 2.29 MB |

**Fix**:
1. Convert all PNG images to WebP or AVIF format
2. Resize images to match display dimensions
3. Use `srcset` for responsive images

### 2. Unused JavaScript - Est. Savings: 258 KiB, 1,350ms

**What**: `index-d312cac4.js` (648 KB) has 41% unused code
**Fix**:
- Code-split Three.js and heavy dependencies
- Lazy-load the 3D planet component

It cross-references the image dimensions in the DOM against the actual file sizes. My 8.87 MB PNG was being displayed at 431×230 pixels. The source image was 2657×1890. I definitely would've missed that scrolling through raw JSON.

The Difference

Lighthouse tells you what's wrong. This tells you what to do about it.

Raw Lighthouse output:

{
  "id": "image-delivery-insight",
  "score": 0,
  "displayValue": "Est savings of 15,654 KiB"
}

What Claude gives you:

ParallaxImageGallery.png:
- Current: 2657×1890 PNG (8.87 MB)
- Displayed: 431×230 px
- Target: 862×460 WebP (~50-100 KB)
- Savings: 8.86 MB (99% reduction)

One tells me there's a problem. The other tells me exactly which file, what size it should be, and what format to use. That's the difference between "I should optimize images" and actually doing it.

Gotchas

Chrome needs to be installed

Lighthouse spawns a headless Chrome instance. If you're on a server without Chrome, this won't work. Use the PageSpeed Insights API instead (I haven't bothered setting that up).

The JSON is huge

~500KB for a single page. If you're reading the file directly in Claude, you might hit context limits on complex pages. The slash command handles this by having Claude extract only the relevant parts, but I've still had it choke on really bloated reports.

Scores vary between runs

Network conditions, server load, whatever. I've seen ±5 points between consecutive runs. Don't obsess over small score differences.

Mobile vs Desktop

Default is mobile throttling. Add --preset=desktop if you want desktop scores. Mobile is usually worse, which is why it's the default.

You can also add more categories (--only-categories=performance,accessibility,best-practices,seo) or run multiple URLs. The slash command is just a prompt template, so modify it for whatever you need.