An LCP resource can be perfectly optimized and still start loading too late. If the browser does not discover that resource until after CSS, JavaScript, hydration, an API response or another dependency completes, the request begins late regardless of file size.
That makes late LCP discovery a timing and dependency problem before it is an image problem.
The first question should not be “Should I preload the hero?” It should be: What prevented the browser from knowing about this resource earlier?
What causes late LCP discovery?
Late LCP discovery happens when the browser does not learn about the LCP resource early in the loading process. Common causes include CSS background images, JavaScript-generated markup, client-side rendering, API dependencies and lazy-loading logic. Diagnosis requires checking the resource start time, request initiator and dependency chain rather than looking only at image size.
What Is Late LCP Discovery?
Browsers cannot request a resource they do not yet know exists.
Late discovery occurs when a critical resource becomes known only after one or more earlier steps have completed.
Early: HTML → LCP image
Late: HTML → JavaScript → component → LCP image
Possible causes include:
- the resource is absent from the initial HTML;
- it is referenced only inside CSS;
- JavaScript creates the element later;
- an API response is required before the component can render;
- framework hydration or client-side rendering must complete first;
- a slider or page builder initializes the hero dynamically;
- lazy-loading logic delays the request;
- the resource sits several steps away from the document in a dependency chain.
Late discovery is contextual. There is no universal “after X milliseconds = late” rule. The key evidence is that the document or earlier dependencies are already available while a user-critical resource begins materially later because the browser did not know about it sooner.
Discovery Delay Is Different From Download and Render Delay
Document → Discovery → Request Start → Resource Complete → Render → LCP
Browser does not know the resource yet
The request cannot begin because an earlier dependency must reveal the resource.
Browser knows the resource but transfer is slow
The request has started, but receiving the response takes too long.
Resource is available but paint is late
The browser has the resource, but CSS, JavaScript, rendering or application state delays presentation.
This article owns the first category: discovery.
For the broader routing model, see the LCP root-cause framework. If the resource loads early and quickly but LCP remains late, see LCP image loads fast but LCP is still slow.
First Confirm the Actual LCP Element
Do not begin late-discovery diagnosis by assuming the visually largest hero image is the LCP element.
First confirm the element the browser is actually reporting.
The LCP candidate can be:
- an image;
- a text block;
- a qualifying CSS background image;
- a video poster;
- another eligible visible element.
The candidate can also change during page load.
Diagnosis starts from the measured LCP candidate, not the design assumption.
Find the LCP Resource in the Network Waterfall
Once the LCP element is confirmed, identify the exact network resource associated with it.
Then:
- find the request in the Network panel;
- compare its start time with the document timeline;
- check when the document became available;
- inspect the request initiator;
- trace the dependency that exposed the resource.
If the element uses a responsive image, inspect the resource the browser actually requested—not just the URL visible in a CMS or editor.
src is not always the final downloaded resource. Browser selection can involve srcset, sizes, viewport conditions and device characteristics.
For the full waterfall methodology, see the network waterfall guide.
When Did the Browser Learn About the Resource?
This is the central question.
Compare:
- document response timing;
- resource request start;
- initiator;
- the requests or application work immediately preceding it.
If the document is already available but the critical resource starts materially later, there is a discovery gap to investigate.
The size of that gap alone does not prove the cause. The dependency path does.
How HTML-Based Discovery Works
A critical resource exposed directly in initial HTML can often be discovered earlier than a resource that only becomes visible after another dependency completes.
HTML path: HTML → image
CSS path: HTML → CSS → background image
JS path: HTML → JavaScript → component → image
This does not mean:
- every hero image must always be hard-coded in HTML;
- every HTML-discovered resource automatically receives the highest priority;
- every non-HTML resource is a performance problem.
The point is simpler: fewer required steps before discovery can allow a critical request to begin earlier.
CSS Background Images and Late Discovery
A background image referenced through CSS can introduce an additional discovery dependency.
A simplified path may look like:
CSS discovery→
CSS download / processing→
background image discovery
That can delay request start compared with a resource that is already exposed to the browser earlier in the document path.
CSS background images are not inherently bad for LCP. The performance question is whether the implementation creates a meaningful discovery delay for the actual LCP resource.
If the waterfall shows a CSS-initiated LCP resource beginning late, inspect the stylesheet dependency and whether the critical resource can be safely exposed earlier.
JavaScript-Generated LCP Resources
If JavaScript creates the LCP element, discovery can depend on both network and CPU work.
A simplified path may be:
JS download→
JS execution→
DOM update→
LCP image request
Examples include:
- client-rendered heroes;
- JavaScript-created images;
- components mounted after startup;
- sliders initialized after page scripts execute;
- page-builder modules that inject the visible asset later.
This does not mean all JavaScript-rendered content is inherently slow.
The question is whether JavaScript is a required dependency before the browser can know the critical resource exists.
API and Data Dependencies Can Delay LCP Discovery
Some critical UI cannot render until data arrives.
JavaScript→
API request→
API response→
component render→
LCP resource
In this pattern, compressing the image does not remove the upstream dependency.
The investigation should ask:
- Does the hero truly need that data before its critical resource can be known?
- Can a critical shell or resource reference exist earlier?
- Can the dependency chain be shortened without changing required functionality?
This is an architecture question, not an image-format question.
Hydration and Client-Side Rendering
A framework-based page may have visible critical content that is not fully available until:
- hydration;
- client-side routing;
- component initialization;
- application state setup;
- runtime rendering.
If the LCP resource only becomes known after these steps, the request can start late even if the file itself is small.
Do not assume hydration is automatically the problem. Confirm the resource’s initiator and the timing relationship first.
Lazy Loading Can Delay a Critical Resource
Lazy loading is useful for resources that do not need to load immediately.
But a critical above-the-fold LCP resource can be delayed if its loading strategy waits for:
- native lazy-loading heuristics;
- a JavaScript lazy-loader;
- Intersection Observer logic;
- a component becoming visible;
- another application event.
Native lazy loading and JavaScript lazy loading are not identical mechanisms, but both can affect request timing depending on implementation.
Do not disable lazy loading globally. If evidence shows the actual LCP resource is being delayed, adjust the loading behavior of that critical resource rather than removing lazy loading from unrelated content.
Sliders, Page Builders and Dynamic Hero Content
Hero sliders and CMS/page-builder output deserve investigation because the critical resource can be represented in very different ways:
- directly in HTML;
- inside inline CSS;
- inside an external stylesheet;
- as a data attribute;
- inside JavaScript configuration;
- inserted only after slider initialization.
A visual editor does not reveal the browser’s actual discovery path.
Inspect generated output and runtime behavior, not the CMS editor interface.
A slider is not automatically an LCP problem. Confirm whether it actually creates a late critical request.
Use the Request Initiator to Trace the Dependency
The request initiator helps answer:
Depending on the request, the initiator may point toward:
- the parser;
- a stylesheet;
- a script;
- a JavaScript call path;
- another resource or browser activity.
For late discovery, initiator evidence is especially valuable because it connects the late start time to the mechanism that exposed the resource.
Example:
Observation: LCP image starts late.
Initiator: JavaScript component.
Dependency: component does not mount until API data resolves.
Hypothesis: API-driven rendering delays LCP resource discovery.
That is much stronger than simply saying “the LCP image loads late.”
How Dependency Chains Push Critical Requests Later
A critical resource may sit several steps away from the document.
CSS path
HTML → stylesheet → background image
JavaScript path
HTML → JavaScript → component → image
Data-driven path
HTML → JavaScript → API → component → image
Lazy path
HTML → lazy logic → visibility condition → image
Each required step creates another opportunity for the critical request to start later.
The engineering goal is not “remove every dependency.”
It is to ask whether the user-critical resource needs to be that far from the document and whether the discovery chain can be shortened safely.
Preload: When It Can Help
Preload can help when a genuinely critical resource is known to the application but normal browser discovery occurs too late.
It can allow the browser to begin fetching the resource earlier than it otherwise would.
Preload is most defensible when:
- the resource is confirmed as user-critical;
- the actual candidate is known;
- normal discovery is measurably late;
- the preload matches the resource the page will really use;
- it does not create duplicate or unnecessary transfer.
It may provide little benefit when:
- the resource is already discovered early;
- render delay is the real bottleneck;
- the wrong responsive candidate is preloaded;
- several hero variants are preloaded unnecessarily;
- the resource is not actually the final LCP candidate.
For the implementation decision, see preload the LCP image.
Preload vs fetchpriority
These mechanisms address different parts of the loading problem.
| Technique | Primary role | What it does not replace |
|---|---|---|
| Preload | Can expose and request a known critical resource earlier | Root-cause diagnosis, server response improvement, render-delay fixes |
| fetchpriority | Provides a fetch-priority hint for a resource the browser knows about | Resource discovery itself |
Discovery first. Priority second.
A resource discovered at 2 seconds can still be too late even if it receives high priority immediately after discovery.
Likewise, a resource can be discovered early but still be scheduled at a lower priority than desired.
These are related but separate problems.
Why High Priority Cannot Fix a Resource the Browser Does Not Know About
Priority hints influence scheduling after the browser has enough information to identify the resource.
If the image does not exist from the browser’s perspective until JavaScript creates it, assigning high priority does not erase the earlier dependency chain.
This is why late-discovery diagnosis must happen before priority tuning.
Early Hints and Other Earlier-Exposure Strategies
Some architectures can expose critical resources before the final HTML response through mechanisms such as Early Hints or server-generated resource hints.
These approaches can be useful in specific systems, but they should not be treated as default fixes for every LCP problem.
The same diagnostic rule applies: first prove that discovery timing is a meaningful bottleneck.
Third-Party Injection Can Create Late LCP Discovery
A third-party script can inject:
- images;
- widgets;
- banners;
- embedded content.
If one of those elements becomes the LCP candidate, its request may depend on the third-party script’s own network and execution path.
Confirm the initiator before attributing the delay to third-party code.
A Practical Late-Discovery Diagnostic Workflow
Identify the actual LCP element
Confirm the browser-reported candidate.
Identify the exact requested resource
Verify the actual image candidate or asset in the Network panel.
Find the request in the waterfall
Locate its request start and completion timing.
Compare request start with document timing
Look for a meaningful discovery gap.
Inspect the Initiator
Determine what caused the browser to request the resource.
Trace the dependency chain
Identify CSS, JavaScript, API, hydration or lazy-loading steps before discovery.
Determine why the resource was not known earlier
Separate architecture from scheduling and transfer issues.
Form a root-cause hypothesis
State which dependency creates the late discovery and what evidence supports it.
Choose the smallest appropriate change
Expose the resource earlier only as much as the evidence justifies.
Verify earlier discovery and LCP impact
Re-check waterfall, candidate selection and LCP timing after the change.
Discovery Pattern → Evidence → Likely Cause → Next Investigation
| Discovery pattern | Evidence | Likely cause | Next investigation |
|---|---|---|---|
| Image request begins after JavaScript execution | Waterfall + Initiator | JavaScript-based discovery | Inspect script or component dependency |
| Background image begins after stylesheet processing | Initiator + CSS timing | Stylesheet dependency | Inspect critical CSS / resource exposure path |
| Resource begins after API response | Waterfall + initiator/dependency chain | Data-driven rendering | Inspect whether critical resource can be known before data completion |
| Resource begins after lazy-loading logic | Initiator + runtime timing | Lazy-loading dependency | Adjust handling of the confirmed critical resource |
| Resource begins after slider or page-builder initialization | Generated markup + waterfall + initiator | Dynamic component discovery | Inspect whether critical asset can be exposed earlier |
Technique → What It Can Help → What It Cannot Fix
| Technique | What it can help | What it cannot fix |
|---|---|---|
| Preload | Late resource discovery when the correct critical resource is known | Server TTFB, JavaScript render delay, incorrect LCP candidate |
| fetchpriority | Scheduling / priority hint after resource discovery | A resource unknown to the browser |
| Image compression | Resource transfer duration | Discovery timing |
| CDN | Delivery and transfer under appropriate conditions | JavaScript or API dependency chains |
| Markup exposure | Can shorten discovery path when architecture permits | Slow transfer or late rendering by itself |
A Late LCP Discovery Decision Tree
Late start → Initiator → Dependency → Earlier exposure decision → Verification
DOES THE LCP RESOURCE START LATE?
│
├─ NO
│ └─ Late discovery is probably not the main issue
│
└─ YES
↓
WHAT INITIATED THE REQUEST?
│
├─ HTML PARSER
│ └─ Check scheduling → priority → loading conditions
│
├─ CSS
│ └─ Inspect stylesheet dependency
│
├─ JAVASCRIPT
│ └─ Inspect execution → component dependency
│
├─ API-DRIVEN RENDER
│ └─ Inspect data dependency
│
└─ LAZY-LOAD MECHANISM
└─ Inspect loading logic
↓
CAN THE RESOURCE BE SAFELY EXPOSED EARLIER?
│
├─ YES
│ └─ Consider markup → preload → loading strategy as appropriate
│
└─ NO
└─ Reduce dependency or redesign the critical path
Common Late-Discovery Diagnosis Mistakes
Preloading immediately because LCP is slow
First prove the actual resource starts late because of discovery.
Not confirming the actual LCP element
The assumed hero may not be the measured candidate.
Not checking the actual image candidate
Responsive selection may produce a different request than the CMS URL.
Looking only at file size
Transfer size does not explain late request start.
Ignoring request start time
Discovery timing is the core evidence.
Ignoring the Initiator
Without it, the dependency that exposed the resource may remain unknown.
Confusing late discovery with slow download
One delays request start; the other extends transfer after start.
Confusing late discovery with render delay
A resource can load early but still paint late.
Using fetchpriority as a discovery fix
Priority does not reveal a resource the browser has not discovered.
Disabling lazy loading site-wide
Target the confirmed critical resource instead.
Preloading multiple hero variants
Unnecessary variants can compete for bandwidth.
Preloading the wrong responsive candidate
The browser may still request another image.
Creating duplicate fetches
A mismatched preload can add work rather than remove delay.
Not re-checking the waterfall after the change
You need evidence that request start actually moved earlier.
Only checking the Lighthouse score
A score change does not prove discovery timing improved.
What Not to Fix Yet
If the LCP resource starts late, do not automatically:
Find the discovery dependency first.
Fix the Discovery Path, Not Just the Image
| Root-cause pattern | Direction |
|---|---|
| Critical resource hidden from initial HTML path | Expose the critical resource earlier when architecture permits |
| CSS dependency | Reconsider the critical resource representation or use preload when justified |
| JavaScript-generated resource | Consider server-rendered or earlier markup exposure, or reduce the dependency when feasible |
| Lazy-loaded LCP resource | Adjust loading behavior for the confirmed critical element |
| API-dependent hero | Reduce the data dependency or expose the critical shell/resource earlier if possible |
| Priority issue after early discovery | Investigate priority hints only after discovery is confirmed |
This is a direction matrix, not a universal implementation checklist.
How to Verify Earlier Discovery
After changing the discovery path, verify the actual behavior rather than assuming the markup change worked.
Check:
- the LCP element is still the expected candidate;
- the exact resource request starts earlier;
- the Initiator path changed as expected;
- no duplicate request appeared;
- the correct responsive candidate is still selected;
- LCP actually improved under comparable conditions;
- network competition did not increase enough to offset the gain;
- layout, rendering and functionality did not regress.
Use the same page state and comparable lab conditions, then monitor field impact when available.
See verify the performance change.
Field vs Lab Impact
Late discovery is often easy to inspect in a controlled waterfall or trace.
Field impact still depends on real-user conditions such as:
- connection quality;
- device capability;
- browser cache;
- page variants;
- user state;
- traffic distribution.
Do not use one lab run to promise a specific field improvement.
Use lab evidence to prove the mechanism changed, then use field data when available to assess real-user impact.
When a Deeper LCP Investigation Is Needed
A deeper investigation is useful when:
Late discovery is often visible in a waterfall, but the reason behind it may sit in HTML generation, CSS, JavaScript, a page builder, a framework or an API dependency. The useful question is not simply whether the resource starts late, but what prevented the browser from knowing about it sooner.
LCP resource starts late, but the dependency is still unclear?
A structured Core Web Vitals investigation can connect request timing, Initiator evidence, dependency chains and browser traces to identify what prevented the browser from discovering the critical resource earlier.
WebPerfLab — Measure → Trace → Diagnose → Fix → Verify
Final Takeaway
Late LCP discovery is a dependency problem before it is an image problem.
Ask:
- When was the resource discovered?
- What initiated it?
- What dependency came before it?
- Can the browser safely know about it earlier?
Then choose the smallest change that shortens the discovery path without creating unnecessary network work.
Trace→
Confirm→
Expose Earlier→
Verify
Do not preload by reflex. Prove the dependency, shorten the discovery path, and verify the result.