Finding the Cause of a Sudden Field LCP Drop

The RUM dashboard shows it on a Monday morning: mobile LCP at the 75th percentile went from 1.8 seconds to 2.7 over the weekend. Nobody deployed. Or somebody did, but the change was a typo fix. Sudden field regressions on static sites are common precisely because so much that affects LCP is not in the repository — third-party scripts, CDN behaviour, consent tools, traffic sources — and because field data blends all of it. Finding the cause is a matter of slicing the data until one segment explains the change, then confirming it in the lab.

This guide works through one such investigation on a 3,000-page Astro marketing and documentation site, which turned out to have two overlapping causes. It shows the RUM fields that make diagnosis possible, the order of questions to ask, and how each candidate was confirmed or ruled out. It belongs to Monitoring Static Sites in Production; the dashboard itself is built in Building a Core Web Vitals Dashboard from RUM Data.

What the RUM Data Needs to Contain

Diagnosis depends on what was recorded. The site's web-vitals beacon sends, for every page view:

onLCP(({ value, attribution: a }) => send({
  metric: 'LCP', value, page: location.pathname, template: document.body.dataset.template,
  element: a.element, url: a.url,                         // the LCP element and its resource
  ttfb: a.timeToFirstByte, loadDelay: a.resourceLoadDelay,
  loadTime: a.resourceLoadDuration, renderDelay: a.elementRenderDelay,
  device: navigator.userAgentData?.mobile ? 'mobile' : 'desktop',
  conn: navigator.connection?.effectiveType, country: cfCountry, ref: document.referrer && new URL(document.referrer).host,
  build: document.querySelector('meta[name=build-id]')?.content,
}));

The four LCP sub-parts are the most useful fields: they say whether the time went into getting HTML, starting the LCP resource, downloading it, or rendering it.

Step 1: Pin Down When and Where

The p75 by hour showed the step change starting Saturday at about 14:00 UTC, not gradually. By template, it was not uniform:

Templatep75 beforep75 afterChange
Landing pages1.9 s3.4 s+1.5 s
Docs articles1.7 s2.0 s+0.3 s
Blog posts1.8 s1.9 s+0.1 s

A step change at one time, concentrated on one template: something changed on Saturday afternoon that affected landing pages most.

Increase in mobile LCP at the 75th percentile per template after the regression Vertical bars of seconds added. Landing pages gained 1.5 seconds. Docs articles 0.3 seconds. Blog posts 0.1 seconds. Mobile LCP change by template 1.5 s Landing pages 0.3 s Docs articles 0.1 s Blog posts
web-vitals RUM, mobile, three days before against three days after Saturday 14:00 UTC.

Step 2: Line It Up With Changes

A timeline of everything that changed around Saturday 14:00, from every source the team could think of:

Time (UTC)ChangeSource
Fri 16:20Deploy: typo fixes in 3 docs pagesDeploy log
Sat 13:55Marketing published a new paid social campaign to landing pagesAd platform
Sat 14:10Tag manager container version 47 publishedTag manager history
Sun 09:00Chrome stable update rolled outBrowser release notes

The Friday deploy predated the change and touched no landing pages. The campaign and the tag manager publish were 15 minutes apart, right at the step. Two suspects.

Step 3: Use the Sub-Parts to Separate the Suspects

LCP sub-parts for landing pages, before and after:

Sub-part (p75, mobile)BeforeAfter
Time to first byte320 ms410 ms
Resource load delay180 ms640 ms
Resource load duration520 ms790 ms
Element render delay140 ms380 ms

Every phase got worse, which suggested two things happening at once. Load delay and render delay — time before the hero image request started, and time between its arrival and paint — point at something competing on the main thread and network early in the load. That fits a tag manager change. Higher TTFB and download time point at slower networks, which fits a traffic change.

LCP sub-parts at the 75th percentile on mobile landing pages before and after Paired bars in milliseconds. Time to first byte went from 320 to 410. Resource load delay from 180 to 640. Resource load duration from 520 to 790. Element render delay from 140 to 380. Where the extra time went on landing pages Before After TTFB 320 ms 410 ms Load delay 180 ms 640 ms Load duration 520 ms 790 ms Render delay 140 ms 380 ms
web-vitals attribution build, mobile landing page views; every phase grew, suggesting two causes.

Step 4: Check the Traffic Mix

Segmenting by referrer settled the first suspect. The new campaign sent 41% of landing page traffic over the weekend, from a social network's in-app browser, mostly on lower-end Android devices with effectiveType of 3g or slow-4g. Restricting the comparison to visitors who did not come from the campaign:

Landing pages, excluding campaignBeforeAfter
LCP p751.9 s2.4 s

So the traffic mix explained about two-thirds of the regression on landing pages — readers on slower devices and networks — and something else explained the remaining 0.5 seconds for everyone.

Step 5: Confirm the Tag Manager Change in the Lab

The tag manager diff between versions 46 and 47 showed one new tag: a heatmap and session-recording script, set to fire on "Page View – DOM Ready" on all landing pages, synchronously injected. WebPageTest on a landing page with a Moto G Power profile, run against the live site with the new tag blocked via WebPageTest's block setting and then unblocked:

Lab, landing pageTag blockedTag active
LCP1.8 s2.4 s
Main-thread time before LCP210 ms690 ms
Requests before LCP1423

That reproduced the remaining half-second. The heatmap tag moved to fire after the window load event and only on a 10% sample of sessions, which marketing agreed was enough for its purpose.

Steps used to find the cause of the field LCP drop Five steps. Find when the change started and which templates it affected. List every change around that time from all sources, not just deploys. Use LCP sub-parts to see which phases slowed. Segment by referrer, device and connection to separate traffic changes from page changes. Reproduce the page change in the lab with the suspect blocked and unblocked. The investigation in order When and where hour, template Every change deploys, tags, campaigns Sub-parts which phase slowed Segment traffic referrer, device Lab confirm block the suspect
Two causes overlapped: a traffic shift explained two-thirds, a new tag the rest.

Step 6: Decide What "Fixed" Means

After the tag change, landing page LCP for non-campaign visitors returned to 1.9 seconds. Overall landing page p75 stayed higher, at 2.6 seconds, while the campaign ran — not a regression in the site but a change in who was visiting. The team made two follow-ups: a lighter landing page variant for the campaign's in-app traffic (smaller hero, no video), which brought campaign visitors' LCP from 3.9 to 2.8 seconds, and dashboard segments by referrer so the next campaign is visible as a traffic change at a glance.

Measured Impact

Measure (mobile, landing pages)Weekend afterAfter fixesTool
LCP p75, all visitors3.4 s2.6 sweb-vitals RUM
LCP p75, excluding campaign2.4 s1.9 sweb-vitals RUM
LCP p75, campaign visitors3.9 s2.8 s (lighter variant)web-vitals RUM
Time from alert to cause identified—3 h 20 minIncident notes

The tag manager now requires a second approver for container publishes that add tags to landing pages.

Pitfalls & Rollback

  • Looking only at deploys. Tag managers, campaigns and CDNs change without them.
  • No LCP sub-parts in RUM. Without them, every cause looks the same.
  • Treating a traffic shift as a regression. Segment by referrer and device first.
  • Relying on CrUX for speed. Its 28-day window hides sudden changes for weeks.
  • Rollback: tag manager versions can be reverted in minutes; that is the fastest test of a tag-related suspect in production.

Conclusion

A sudden field LCP drop on a static site is often not in the site's code. Here it was two overlapping causes: a campaign that brought slower devices and networks, and a heatmap tag published in the tag manager on the same afternoon. RUM with LCP sub-parts, a timeline of every change from every source, segmentation by traffic, and a lab test with the suspect blocked separated them in an afternoon.

FAQ

Why did my field LCP get worse when nothing was deployed?

Field LCP depends on more than your code. Third-party scripts change without a deploy, CDN configuration or cache behaviour can change, traffic can shift to slower devices or regions through a campaign, and browsers update. Segmenting field data by page template, device, country and referrer usually shows which of these it is.

How quickly does CrUX show an LCP regression?

The public CrUX dataset is a rolling 28-day window, so a sudden regression appears gradually and takes up to four weeks to show fully, and the monthly BigQuery data lags further. Your own RUM data with the web-vitals library shows a change within hours, which is why it is worth collecting even if you also watch CrUX.

What should real user monitoring record to diagnose LCP?

The LCP value and element, the LCP sub-parts from the attribution build of web-vitals, which are time to first byte, resource load delay, resource load duration and element render delay, plus page template, device class, connection type, country and a build identifier. The sub-parts point at the phase that got slower, which narrows the cause quickly.

Can a lab test reproduce a field LCP regression?

Often, once you know which pages and conditions are affected. Run WebPageTest or Lighthouse on an affected template with a matching device and connection profile, before and after the suspected change, and compare filmstrips and waterfalls. If the lab does not reproduce it, the cause is probably in traffic mix or real network conditions rather than the page.

Filed underFixes