Performance Tracing with Chrome DevTools MCP and The AI Agent

Performance Tracing with Chrome DevTools MCP and The AI Agent

In a previous post, Improving Lighthouse Performance with Image Optimization, I described a manual process of auditing image delivery, converting to WebP, and tuning LCP/CLS to push my Lighthouse score from 56 to 85. That workflow was effective but slow — run a trace, read the output, decide what to fix, repeat.

This time I went further. Instead of running Lighthouse by hand, I used the Chrome DevTools MCP, a tool that gives AI Agents direct access to a Chrome browser session. The result was a faster, more iterative loop: The AI Agent ran the traces, read the insights, proposed fixes, and measured the results, all within the same conversation.

How the Chrome DevTools MCP works

The Chrome DevTools MCP exposes browser automation primitives (navigate, evaluate script, take screenshots, start/stop performance traces) as tools that The AI Agent can call directly. With Chrome launched in remote debugging mode, The AI Agent can open a URL, run a performance trace, parse the LCPDiscovery, CLSCulprits, and ImageDelivery insights, and reason about them without you switching tabs.

The workflow looked like this:

  1. Launch Chrome with --remote-debugging-port=9222
  2. Ask The AI Agent to trace a page
  3. The AI Agent navigates, starts the trace, interacts with the page, stops the trace, and reads the insights
  4. The AI Agent proposes a fix, I apply it and deploy
  5. The AI Agent re-runs the same trace and compares metrics

What made this faster than doing it manually: no copy-pasting metrics, no explaining what the Lighthouse panel said, no context switching. The entire trace-analyse-fix cycle lived in the conversation.

The page under test: /moments

My moments page is a photo gallery with 92+ photos loaded in batches of 12 via a "Load More" button. Each photo opens a modal with carousel navigation and metadata. It is one of the heavier pages on the site (a good stress test).

I ran three separate trace types: page load (LCP), repeated "Load More" interactions (INP + image delivery), and full modal navigation across all 92 photos (INP + CLS).

Finding 1: LCP image was deprioritised

The first trace flagged LCPDiscovery — the first grid image had loading="lazy" applied unconditionally, so the browser only discovered and fetched it after JS hydration.

Fix: loading="eager" and fetchPriority="high" on the first image only.

MetricBeforeAfter
LCP327 ms219 ms
Load delay48 ms5 ms
Render delay238 ms177 ms

Finding 2: Grid thumbnails served at full resolution

The ImageDelivery insight flagged 7.4 MB of avoidable downloads on a single "Load More" click. All 92 grid thumbnails were being served at original resolution (up to 3072×3072) despite being displayed at ~400px per cell.

Fix: A new script (scripts/images/generate-moment-thumbs.js) reads all the photos in the gallery and generates a <name>-thumb.webp at 800px max for every grid photo. Full-res originals are preserved and still used in the modal.

MetricBeforeAfter
Download per "Load More" (12 images)~7.4 MB~650 KB
Total grid image storage (92 images)32.19 MB7.24 MB
LCP (compounded with fix 1)327 ms120 ms

The LCP improvement compounded: the thumbnail is now small enough to load and render before hydration finishes, collapsing render delay from 238 ms to 73 ms.

Finding 3: CLS 0.46 during modal navigation

After deploying thumbnails, a third trace navigated through all 92 photos programmatically (80 ms per step). CLS spiked to 0.46 — well above the "Bad" threshold of 0.25.

The root cause: .panel in MomentModal.tsx used max-height: 90vh. Because max-height allows the panel to grow and shrink with image content, every photo swap with a different aspect ratio reflowed the panel and accumulated layout shift. Over 92 navigations that adds up fast.

Fix: One CSS change — max-height: 90vhheight: 90vh. With a fixed height the panel never reflows. object-fit: contain on .photo handles all aspect ratios without distortion.

MetricBeforeAfter
CLS (92-photo modal navigation)0.46 ⚠️0.01

The remaining 0.01 is unrelated to modal image swaps.

What I would have missed without scripted traces

The CLS issue in particular would have been very hard to catch manually. It only accumulated to 0.46 over 91 rapid navigations. A normal user browsing a few photos at a time would see a much lower CLS score — low enough to fly under the radar in a standard Lighthouse audit. Running the trace programmatically across all 92 photos made the pattern visible.

The faster loop also meant I could verify each fix before moving to the next one, rather than batching everything and guessing which change caused which improvement.

Summary of all metrics

MetricBaselineAfter all fixesDelta
LCP327 ms120 ms-63%
INP (modal navigation)167 ms40 ms-76%
CLS (modal navigation)0.46 ⚠️0.01-98%
Grid image download (per batch)~7.4 MB~650 KB-91%

Glossary

LCP — Largest Contentful Paint Measures how long it takes for the largest visible element (image, heading, or block of text) to finish rendering in the viewport. A good LCP is under 2.5 s. It is the primary signal for perceived load speed.

INP — Interaction to Next Paint Measures the latency between a user interaction (click, tap, key press) and the next frame the browser paints in response. A good INP is under 200 ms. It replaced FID as a Core Web Vital in 2024.

CLS — Cumulative Layout Shift Measures the total amount of unexpected visual movement that occurs during the page's lifetime. A good CLS is under 0.1. High CLS means elements jump around as the page loads, which disrupts reading and can cause accidental clicks.

FCP — First Contentful Paint Measures when the browser renders the first piece of DOM content (text, image, SVG). Marks the point where the page stops looking blank to the user.

FID — First Input Delay (deprecated — replaced by INP) Measured the delay between a user's first interaction and the browser's response. Retired as a Core Web Vital in March 2024.

TTFB — Time to First Byte Measures the time from the browser sending a request to receiving the first byte of the server response. Affected by server processing time, CDN configuration, and network latency.

Changelog (2)
  • Added Glossary section with definitions and MDN links for LCP, INP, CLS, FCP, FID, and TTFB.
  • Initial publish.