How to tell the browser explicitly which resources should load first
Browsers constantly make decisions about which resource to request next while loading a page. The fetchpriority attribute lets you override those heuristics on purpose and tell the browser exactly which images, scripts, or links are actually critical for the first paint.
Table of Contents
- 1. Why browser heuristics fall short
- 2. The three values of fetchpriority: high, low, and auto
- 3. fetchpriority=high for the LCP image
- 4. fetchpriority=low for secondary resources
- 5. How it interacts with the preload scanner
- 6. Prioritizing CSS and JavaScript
- 7. Measuring the actual effect on LCP
- 8. Common mistakes when applying fetchpriority
- 9. Browser support and fallback strategy
- 10. Summary
- 11. FAQ
1. Why browser heuristics fall short
Browsers rely on internal heuristics to decide the load order of resources. Factors such as resource type, position in the document, and whether a resource is render-blocking all feed into this prioritization. These heuristics work well in many cases, but they are blind to the actual visual and business relevance of a given resource. An image placed far down in the HTML but rendered as the first visible element, for example through CSS positioning, is often assigned a priority that is far too low.
This is exactly where fetchpriority comes in. The attribute lets developers pass their own knowledge about a resource's true importance directly to the browser, instead of relying entirely on heuristics. This matters especially for the Largest Contentful Paint (LCP), since the priority of the LCP element has a direct and often substantial impact on that core metric. Used correctly, fetchpriority can improve LCP by several hundred milliseconds without touching any other part of the code.
2. The three values of fetchpriority: high, low, and auto
The attribute recognizes exactly three values. auto is the default and leaves the decision entirely to the browser's heuristic. high tells the browser that this resource should be preferred over other resources in the same priority class. low does the opposite, pushing a resource further back in the queue so more important resources get their turn first.
The attribute is supported on the img, link, and script elements, as well as programmatically through the priority option of the fetch() init object. The syntax is intentionally simple, so it drops into existing templates with little effort. It's worth noting that fetchpriority influences load order within the same priority class, but it doesn't suddenly make a resource render-blocking or the reverse.
<!-- LCP image: high priority, no lazy loading -->
<img
src="/media/hero-product.webp"
alt="Product view"
fetchpriority="high"
loading="eager"
width="1200"
height="600"
>
<!-- Secondary script: low priority -->
<script src="/js/consent-banner.js" fetchpriority="low" defer></script>
<!-- Programmatic fetch with priority -->
<script type="text/plain" data-csp="true">
fetch('/api/recommendations', { priority: 'low' })
.then(response => response.json())
.then(data => renderRecommendations(data));
</script>
3. fetchpriority=high for the LCP image
The most common and most effective use case is marking the LCP image with fetchpriority="high". In many layouts, the largest visible element in the initial viewport is a hero image or a product photo, which the browser initially treats like any other image. Without explicit prioritization, this image competes with other resources such as web fonts, analytics scripts, or lower-priority images for bandwidth and connection slots.
Setting fetchpriority="high" pushes the request for the LCP image into the queue early with elevated priority. Combined with loading="eager", explicitly disabling lazy loading for that one image, this ensures the browser issues the request as early as possible instead of queuing it behind less important resources. This combination has become one of the best documented and easiest to implement LCP optimizations available today.
4. fetchpriority=low for secondary resources
The low value is the counterpart, suited to resources that need to load eventually but play no role in the first paint. Typical examples include below-the-fold images, social media icons in the footer, non-critical third-party scripts, or prefetch resources for later interactions. Without a low priority, these resources would otherwise compete with the LCP image or critical CSS for the same limited number of parallel connections.
fetchpriority="low" is particularly effective on images in carousels or product listings, where only the first visible item is genuinely urgent. Embedded iframes for advertising or tracking pixels also benefit from a low priority value, since these elements rarely contribute to perceived load speed. In practice, a deliberate combination of high for a few critical elements and low for clearly secondary elements delivers the biggest gains, while blanket assignment adds little value.
5. How it interacts with the preload scanner
Modern browsers run a so-called preload scanner that works alongside the main HTML parser, scanning ahead for resources like images, scripts, and stylesheets so their download can start early. The fetchpriority attribute is evaluated directly by the preload scanner, provided it is present statically in the HTML rather than added later through JavaScript. That means prioritization kicks in at a very early stage of page construction, long before the DOM is fully built.
If fetchpriority is instead set by a script after initial parsing, that early advantage is lost, because the preload scanner has already recorded the resource with its default priority by that point. For maximum effect, the attribute should always be delivered as a static HTML attribute in the server response, not added later through hydration or framework logic. This is a point that is frequently overlooked in practice, leaving teams wondering why a seemingly correct priority setting shows no measurable effect.
6. Prioritizing CSS and JavaScript
Beyond images, fetchpriority is also worth using on stylesheets and scripts. A critical stylesheet needed for the first visible area of the page can be marked fetchpriority="high" so it loads ahead of less important CSS files, such as print stylesheets or styles for rarely used components. With scripts the picture is more nuanced, since async and defer already have a substantial effect on execution order, and fetchpriority mainly influences download order within the same execution class.
A sensible use case is a script central to interactivity, such as a framework bundle, marked fetchpriority="high", while analytics or consent-management scripts get fetchpriority="low". This ensures user-facing functionality isn't held back by third-party resources, even though both script types can technically load asynchronously.
7. Measuring the actual effect on LCP
Without measurement, any prioritization remains a guess. Chrome DevTools shows a dedicated Priority column in the Network panel for every request, letting you check directly whether fetchpriority actually had the expected effect. The PerformanceResourceTiming API also exposes the same value programmatically through the fetchPriority field, which works well for automated real-user monitoring.
For reliable conclusions, a comparison based on real user data (field data) is preferable to lab measurements alone, since network conditions and device performance strongly affect the actual outcome. Tools such as WebPageTest also allow a direct waterfall comparison between a version with and without fetchpriority, making the effect on the LCP request's start time visible and quantifiable. Well-documented case studies show LCP improvements of 10 to 30 percent on pages with a clearly identifiable hero image that had previously been assigned a low priority.
8. Common mistakes when applying fetchpriority
The most common mistake is handing out fetchpriority="high" to too many resources at once. When too many elements are marked as high priority, the prioritization loses its effect, because all the resources are once again competing for the same limited capacity, just now all at the same elevated level. It's better to restrict high strictly to the one LCP element and question every other candidate critically.
Another widespread mistake is combining fetchpriority="high" with loading="lazy" on the same image, which contradicts itself and in practice results in the browser giving lazy loading the upper hand, so the high priority has no effect. Setting the attribute later via JavaScript, as described in the preload scanner section, is equally problematic, since it wipes out the crucial timing advantage.
9. Browser support and fallback strategy
fetchpriority is supported by all Chromium-based browsers as well as current versions of Firefox and Safari, and support has improved significantly over the past few years. Because the attribute is purely additive, missing support in older browsers is not a functional problem: the attribute is simply ignored, and the page behaves exactly as before, with no errors or rendering issues.
That means no separate fallback logic or feature detection is needed, which makes fetchpriority one of the lowest-risk performance optimizations available. Progressive enhancement is essentially built in: users on modern browsers benefit from a faster LCP, while users on older browsers experience exactly the previous behavior. This ratio of low implementation effort to potentially significant performance gain is why fetchpriority should be one of the first things checked during LCP optimization.
| Resource type | Recommended value | Reasoning |
|---|---|---|
| LCP hero image | high | Direct impact on the LCP core metric |
| Carousel images (from the second slide onward) | low | Not visible during the initial paint |
| Critical stylesheet for the first viewport | high | Blocks rendering, must arrive early |
| Analytics and tracking scripts | low | No impact on perceived load speed |
| Web fonts for visible text in the first viewport | high | Avoids invisible text while loading |
Mironsoft
Web performance, Core Web Vitals, and load time optimization
Load times that don't make users bounce before the page is even visible?
We review existing websites for slow Core Web Vitals, bloated JavaScript bundles, and unnecessary render blockers, then build a performance foundation that stays measurable instead of just looking good once.
Performance Audit
Systematically measuring and fixing Core Web Vitals, load waterfall, and render blockers.
Bundle Optimization
Specifically reducing JavaScript and CSS bundle size and improving code splitting.
Monitoring Setup
Establishing continuous performance monitoring instead of a one-time snapshot.
10. Summary
fetchpriority
Goal
Deliberate control over the load order of critical resources
Core value
high for the LCP element, low for secondary resources
Requirement
Static HTML attribute so the preload scanner can pick it up
Measurement
Network panel Priority column and the PerformanceResourceTiming API