CLSCore Web VitalsAIAIReportTutorial

How to Fix Cumulative Layout Shift with AI

Fix Cumulative Layout Shift with AI. Hand the model the shifting nodes from an AIReport, reserve their space, and re-scan until lab CLS is 0.1 or less.

PageSpeed Exporter Team··6 min read

To fix Cumulative Layout Shift (CLS) with AI, give the model the nodes that actually moved. A good CLS is 0.1 or less. Lighthouse weights that metric at 25 points. The AIReport lists each shifting element with a selector and a shift score, which is the part a generic "add width and height" answer does not have.

The cause-by-cause manual, with WordPress and Shopify detail, is How to Fix Cumulative Layout Shift. This page is the AI loop: export, point the model at the culprits, ship the space reservation, scan again.


What you are asking the model to change

CLS is unexpected movement. Each shift is impact fraction times distance fraction. The lab score is the sum. A cookie banner that covers 40% of the screen and moves content 15% of the viewport height scores 0.4 × 0.15 = 0.06 by itself.

  • 0.1 or less is good. Stop. targetFor90 is 0.1.
  • 0.1 to 0.25 needs improvement. Fix the top one or two shiftScore rows.
  • Above 0.25 is poor. The largest row is usually most of the 25 points.
scorePlan puts pointsAtRisk next to the metric. A CLS near 0 can cost about 25 performance points. A CLS already under 0.1 costs almost none. If LCP or Total Blocking Time has more points at risk, fix that metric first and come back. The matching LCP loop is How to Fix Largest Contentful Paint with AI.

Lab CLS and Search Console CLS are different clocks. fieldData is 28 days of Chrome users. The next AIReport shows whether your diff stopped the shift in the lab. The field score follows later.


The rows that name the element

Run the URL on PageSpeed Exporter, mobile first. Download AIReport (JSON) or use Copy Prompt + JSON. Then look only at these fields:

  • scorePlan → cumulative-layout-shift — current value, pointsAtRisk, and targetFor90 (0.1)
  • layout-shift-elements → details.items — selector, snippet, and shiftScore for each node
  • cls-culprits-insight — why that node moved: unsized image, web font, or injected banner
  • unsized-images — images that had no width and height
  • passedAuditIds — do not restyle checks that already pass

Sort the items by shiftScore, not by how annoyed you are at the footer. A hero image at 0.18 matters more than a badge at 0.01.

{
  "id": "layout-shift-elements",
  "affectsMetrics": ["cumulative-layout-shift"],
  "details": {
    "items": [
      { "selector": "img.hero", "snippet": "<img class=\"hero\" src=\"/hero.jpg\">", "shiftScore": 0.18 },
      { "selector": "#cookie-banner", "snippet": "<div id=\"cookie-banner\">", "shiftScore": 0.09 }
    ]
  }
}

That is the whole assignment. Two nodes. Everything else on the page stays put.


Prompt

You are fixing Cumulative Layout Shift. The JSON is an AIReport from PageSpeed Exporter.

1. Read scorePlan for cumulative-layout-shift. State numericValue, pointsAtRisk, and targetFor90.
2. List details.items from layout-shift-elements and cls-culprits-insight, highest shiftScore first.
3. For each item above 0.01, write a diff that reserves space before the node loads.
   Use the selector and snippet. Do not edit unrelated components.
4. Prefer width and height, aspect-ratio, or min-height. Do not animate top, left, or height.
5. Skip ids in passedAuditIds.
6. Stack: [Next.js / WordPress / Shopify / plain HTML].
7. Tell me the CLS numericValue to expect on the next mobile scan.

If a shift is a late cookie banner or chat widget, reserve a slot or overlay it. Do not push the document down.

The model will often answer with a global image rule. Send it back to the selector list. One unsized hero is a one-line fix. A sitewide image plugin is a different project, and the existing CLS cause guide covers that.


What the diff should look like

For the excerpt above, the hero needs dimensions and the banner needs a reserved slot.

<img class="hero" src="/hero.jpg" width="1200" height="800" alt="Hero">
#cookie-banner {
  min-height: 64px;
}

If the banner is injected and you cannot reserve flow space, position it fixed so it overlays instead of pushing layout. That is still a CLS fix. Web-font shifts want font-display: swap and a fallback with a similar size, not a new font family. Ads and embeds want a box with aspect-ratio before the third-party script runs.

On Next.js, next/image with explicit width and height (or fill plus a sized parent) covers the hero row. On WordPress, the block that matches img.hero needs width and height in the markup, which a performance plugin can backfill. Do that after the report names the image, so you are not resizing the whole media library on a guess.

Example re-scan: CLS 0.32 → 0.07. The 0.18 image shift and the 0.09 banner shift are gone. pointsAtRisk for CLS drops from the high teens to about 0, because 0.07 is under the 0.1 target. The performance score moves by the CLS weight you actually recovered, which is the number in scorePlan, not a rounded promise.

Prove it, then decide if you need more scans

Run the same mobile URL again.

  • cumulative-layout-shift.numericValue ≤ 0.1 means the lab check passed
  • The old selectors are absent from layout-shift-elements, or their shiftScore is near 0
  • A new node at the top of the list means the fix moved the shift somewhere else. Paste the new AIReport and repeat once

Anonymous use is 2 preview reports. A free account is 5 mobile reports a month. CLS on a homepage, a product template, and a verification scan is most of that allowance. Starter is 50 reports, desktop as well as mobile, and a before/after comparison so you can show the 0.32 → 0.07 pair. Pro adds a batch ZIP when the same banner shifts every client template.

After a free account has used all 5 reports in the month, the first paid month is $5 on Starter (then $9) or $15 on Pro (then $29). Until then, the prices on the pricing page stay $9 and $29. The thank-you rate is for people who already ran the free reports, which is this workflow.


Further Reading


Sources


Further reading

Try it yourself

Run a free Lighthouse audit on any URL and get the full JSON report for your AI agent — no account required.

Analyze a URL for free