Back to HTML Pub

The Performance Budget for AI-Generated Landing Pages: What Claude's Code Costs You in Ad Load Time

Michael Sacca•
AI-Native Publishing
Landing Pages
Performance

There's a moment every person who has launched an AI-built landing page knows. The page looks great. The copy is tight. You send the URL to a colleague, and three seconds later — nothing. White screen. Then the hero finally paints, and your Tailwind-built masterpiece arrives wearing four hundred kilobytes of unused CSS like a raincoat in summer.

You paid for that click. Google's page experience documentation has told advertisers for years that slow pages convert worse and rank worse. And Claude, bless it, will never volunteer that your page is heavy — because you never asked it to be light.

This post defines the budget. Not "make it fast" — a number, per asset, that your generated page is allowed to cost. Then the exact prompts that make Claude comply before a dollar of ad spend touches the URL.

Why LLM-generated code is predictably heavy

The bloat isn't random. LLMs generate the same performance debt over and over because they're optimizing for what you asked to see — a page that looks right — and speed is invisible in a chat window. The recurring culprits:

Unused Tailwind (or Bootstrap) in full. Ask Claude for "a landing page with Tailwind" and it will link the full CDN build — roughly 300KB uncompressed, around 80-90KB gzipped — to use maybe 15% of the utility classes. The Tailwind CDN play CDN documentation itself says it's not designed for production. Claude uses it anyway, because it's the fastest thing to write.

Duplicate font loads. This is the sneakiest one. Claude will happily put a Google Fonts <link> in the <head>, and an @import in the stylesheet, and a font-display block in a <style> tag — three separate network requests for the same two weights of Inter. I've audited generated pages with the same font family requested four times.

Inline JavaScript that blocks the first paint. Generated pages love a <script> tag right after the opening <body>, synchronously loading, doing something trivial like a scroll effect. Every byte of it sits in front of your hero image.

Unoptimized hero images. Claude can't see your image. It will happily reference a 4MB PNG straight from your Downloads folder with no width/height attributes, no srcset, and a <img loading="eager"> it didn't need.

Everything at once. No lazy loading, no deferred scripts, no preconnect hints — because you never mentioned performance, so the model didn't generate for it.

Individually, each of these is small. Together they're the difference between a page that paints in 1.2 seconds and one that paints in 4.

The budget

Numbers first, vibes never. Here's the budget an AI-generated landing page has to pass before it sees paid traffic. These thresholds are drawn from Google's Core Web Vitals thresholds, which define "good" as:

MetricBudgetWhy this number
LCP (Largest Contentful Paint)≤ 2.5sGoogle's "good" threshold; anything slower reads as "broken" on mobile
INP (Interaction to Next Paint)≤ 200msThe responsiveness metric that replaced FID in March 2024
CLS (Cumulative Layout Shift)≤ 0.1No font/image elements without declared dimensions
Total page weight≤ 500KBA single-purpose landing page has no excuse to exceed this
CSS shipped≤ 50KBFull Tailwind CDN fails this by design — inline the classes you use
Font requests≤ 2One family, two weights, loaded once
Render-blocking scripts0Everything defer or at the bottom

That last three lines are where generated code dies. Claude's default output ships 80-90KB of CSS alone. It fails the budget before a single image loads.

One note on testing: Lighthouse in Chrome DevTools measures lab data — your page on a simulated connection. What Google's ranking systems and real visitors experience is field data. Run Lighthouse first because it's instant, then verify against PageSpeed Insights, which reports both.

The three-pass fix loop

Don't ask Claude to "make it fast." Vague prompts produce vague code. Run three specific passes:

Pass 1: The audit prompt

Paste the page's HTML into Claude with this:

Audit this landing page against this budget: LCP under 2.5s, max 
500KB total, max 50KB CSS, max 2 font requests, zero 
render-blocking scripts. List every violation with the exact line, 
the KB it costs, and the fix. Do not rewrite anything yet.

This works because it forces the model to enumerate before it edits — you get a line-by-line receipt of the damage instead of a confident "I've optimized it" that may have fixed one thing.

Pass 2: The surgical rewrite

Fix only these violations:
1. Remove the Tailwind CDN and replace it with only the CSS 
   classes actually used in this HTML, inlined in a <style> tag.
2. Consolidate all font loading into one <link> with preconnect 
   and display=swap. Delete any @import or duplicate font-family 
   declarations.
3. Add defer to every script tag.
4. Add width and height attributes to every <img>, and 
   loading="lazy" to everything below the fold.
Do not change any visible content, layout, or copy.

That last line is load-bearing. Without it, the model will "improve" your headline while it's in there.

Pass 3: The regression check

Re-run Lighthouse. If CSS is still over 50KB, the likely culprit is that the inlined stylesheet kept utility classes for elements Claude imagined might exist. Run:

Diff the inlined CSS against the actual class attributes in the 
HTML. Remove any selector that isn't referenced. Report the KB saved.

Two or three loops of this typically takes a generated page from 80+ Lighthouse down to the mid-90s. I've seen the Tailwind-CDN-to-inlined-CSS swap alone cut total weight by more than half.

One thing prompts can't fix

There's a ceiling to prompt-based optimization: Claude cannot compress an image it can't see, and it can't measure real-user data. Two things to handle outside the chat:

  • Images are your job. Run hero images through Squoosh before they go anywhere near the page, and serve WebP. A 4MB PNG becomes a 180KB WebP with no visible difference — that's often the single biggest LCP win available.
  • Field data is your job. Lighthouse passing doesn't mean your visitors' phones agree. After a week of traffic, check the Core Web Vitals report in Search Console and feed any failing real-user metrics back into Claude with the audit prompt — "this is what actual devices measured, fix accordingly."

Make it a standing rule, not a one-off

If you're generating pages at the pace most AI-native publishers are — a new variant per ad group, a new page per offer — you can't hand-audit every one. Bake the budget into your generation prompt from the start:

Build this landing page with: no CSS framework CDN (inline only 
used styles), exactly one font with two weights, all scripts 
deferred, dimensions on all images, total weight under 500KB. 
Then self-audit against that list and report violations before 
showing me the code.

The self-audit instruction is the part most people skip, and it's the part that does the work. A model that has to grade its own output before showing it to you catches the duplicate font load that you'd otherwise catch on launch day, in a panic, with the campaign already approved.

For the rest of the launch checklist — meta tags, forms, the things that break in ways Lighthouse won't catch — that's covered in Before You Deploy: The 12-Point Checklist for Code ChatGPT or Claude Handed You. Speed is one line on that list. It's the line your ad budget feels first.

Keep Reading