Fetchpriority Beyond the Hero Image
fetchpriority="high" on the LCP image has become standard advice, and it works: the browser moves that image ahead of other images, and LCP improves. But the attribute has two directions and applies to more than images. The browser's default priorities are guesses — images in the viewport get medium-high priority once layout knows they are visible, scripts at the end of the body get low priority, fetch() calls get high — and on a real page several of those guesses are wrong. Telling the browser what matters, and what does not, is often worth as much as the hero hint itself.
This guide applies fetchpriority across a static marketing site: demoting carousel slides and decorative images that compete with the LCP image, lowering priority for non-critical iframes and scripts, raising a data fetch that the first interaction depends on, and measuring each change in the lab and the field. It is part of Resource Hints and Navigation Speed, building on Optimizing LCP on Astro with Priority Hints.
Prerequisites
- Pages whose waterfalls show critical resources waiting behind less important ones (WebPageTest's "Priority" column or DevTools' Network panel with the Priority column enabled).
- Field LCP and INP data to check that changes help readers, not just the lab.
- Control over the markup of images, iframes and scripts on the key templates.
Step 1: Read the Priorities in the Waterfall
The Network panel's Priority column shows each request's initial and final priority. On the site's home page, loaded on a throttled mobile profile, the LCP was the first slide of a hero carousel, and the waterfall showed:
| Request | Initial priority | Started | Finished |
|---|---|---|---|
Carousel slide 1 (LCP, fetchpriority=high) | High | 240 ms | 1,310 ms |
| Carousel slide 2 | Low → High (in viewport, hidden) | 250 ms | 1,380 ms |
| Carousel slide 3 | Low → High | 250 ms | 1,420 ms |
| Logo strip (6 images) | Low → High | 260 ms | 1,520 ms |
| YouTube embed iframe | High | 300 ms | 900 ms |
| Newsletter form script | Low | 1,500 ms | 1,690 ms |
The hero hint was in place, but slides 2 and 3 — positioned in the viewport and hidden with opacity: 0 — were promoted to high priority once layout found them "visible", and shared bandwidth with slide 1 on a slow connection. The logo strip and the video iframe competed too.
Step 2: Demote What Is Visible but Not Important
Hidden carousel slides, decorative images and logo strips near the top are the classic cases. Mark them fetchpriority="low" so they stay behind the LCP image:
<div class="carousel">
<img src="/img/slide-1-960.avif" srcset="…" sizes="100vw" width="1920" height="900" alt="…" fetchpriority="high">
<img src="/img/slide-2-960.avif" srcset="…" sizes="100vw" width="1920" height="900" alt="…" fetchpriority="low" decoding="async">
<img src="/img/slide-3-960.avif" srcset="…" sizes="100vw" width="1920" height="900" alt="…" fetchpriority="low" decoding="async">
</div>
<ul class="logos">
<li><img src="/img/logos/acme.svg" width="120" height="40" alt="Acme" fetchpriority="low"></li>
…
</ul>
loading="lazy" is not the right tool for slides 2 and 3: they are in the viewport as far as layout is concerned, so lazy loading would start them anyway, and a carousel that advances automatically needs them soon. Low priority lets them load right after the critical resources.
Step 3: Lower Iframes and Non-Critical Scripts
Iframes default to high priority for their document request, which is rarely what a video embed deserves. The site's product video became a facade (a thumbnail and play button that loads the iframe on click, as in Lazy-Loading YouTube Embeds on Static Sites); where an iframe must load immediately, fetchpriority="low" on it keeps it behind the hero.
Scripts are the opposite case: module scripts load at low priority by default. The newsletter form's validation script is only needed when the reader interacts with the form near the bottom of the page, so its low priority is correct. But the site's search dialog, opened from the header by many readers in their first seconds, lazily fetched its index with fetch() — high priority by default — competing with the LCP image when readers hovered the search button early. Lowering that fetch during page load was a one-line change:
const index = await fetch('/search-index.json', { priority: document.readyState === 'complete' ? 'high' : 'low' });
After load, the fetch runs at high priority so an open search dialog fills quickly; during load it yields to the page's critical resources.
Step 4: Raise What the First Interaction Needs
On the documentation templates the situation was reversed. The most common first interaction was opening the sidebar navigation on mobile, which depended on a small navigation data file fetched by the menu island. Because the island hydrated on idle, the fetch started late and the first tap on the menu sometimes waited for it. Preloading the data file with fetchpriority="high" and as="fetch" made it arrive with the page:
<link rel="preload" href="/nav/docs.json" as="fetch" type="application/json" crossorigin fetchpriority="high">
INP for the menu interaction at p75 fell from 210 ms to 120 ms, since the handler no longer waited on the network. It was the only resource raised above default on those templates.
Priorities During Client-Side Navigation and Prefetch
Priorities also matter after the first page. Sites that prefetch the next page on hover, as in Prefetching Links in Astro, issue those prefetches at the lowest priority by default, which is correct: they should never compete with the current page. Speculation rules that prerender a likely next page run in a separate context with their own resource loading, and the images inside that prerendered page follow the same fetchpriority attributes, so a well-prioritised hero loads first there too. The one thing to avoid is raising the priority of prefetches themselves — a "prefetch with high priority" competes with the current page's own late-loading images and can make scrolling on slow connections visibly worse.
Checking priorities after changes is easy to forget, because nothing breaks when they are wrong; pages are just slower than they need to be. The team added the WebPageTest waterfall for the home page to the weekly performance review, which is how the early search fetch was spotted in the first place.
A final habit worth adopting: when adding any image, iframe or early fetch to a high-traffic template, decide its priority explicitly in the pull request rather than leaving it to the default, and note the reason in a comment next to the attribute.
Measured Impact
Home page and docs template, Lighthouse mobile median of five and two weeks of field data:
| Measure | Before | After |
|---|---|---|
| Home: LCP slide finished (lab) | 1,310 ms | 890 ms |
| Home: LCP p75 mobile (field) | 2.3 s | 1.8 s |
| Home: requests competing with LCP in first second | 11 | 3 |
| Docs: menu interaction INP p75 | 210 ms | 120 ms |
| Docs: LCP p75 (unchanged by preload) | 1.62 s | 1.61 s |
Pitfalls & Rollback
- High on everything. Priority is relative; raising many resources raises none.
- Low on the LCP image or first-seen content. It delays exactly what readers look at.
- Using
loading="lazy"for in-viewport images. It does not help and can delay them; use low priority. - Assuming defaults are right. Hidden in-viewport images and early
fetch()calls are frequently mis-prioritised. - Rollback:
fetchpriorityis an attribute; removing it restores the browser default, and unsupported browsers ignore it already.
Conclusion
fetchpriority is a two-way control. Raise the one resource that decides LCP, or the one fetch the first interaction needs, and lower the images, iframes and fetches that compete with them while the page loads. On this site most of the gain came from demoting — hidden carousel slides, a logo strip and an early search fetch — which brought the home page LCP image in 400 ms sooner without touching the image itself.
FAQ
What does the fetchpriority attribute do?
It gives the browser a hint about the relative priority of a resource compared with others of the same type. High raises it, low lowers it, and auto leaves the browser's default. It works on img, link, script and iframe elements and as an option to fetch.
Is fetchpriority only useful on the LCP image?
No. Lowering the priority of images that are visible but not important, such as later carousel slides or decorative images near the top, frees bandwidth for the LCP image. Raising the priority of a script or data fetch that the first interaction depends on can improve responsiveness.
Does fetchpriority low delay images too much?
It delays them relative to high-priority resources on a busy connection, which is the intent. On an idle connection they load promptly. Do not set low on the LCP image or on images a reader is likely to look at first.
Which browsers support fetchpriority?
Chromium browsers since version 101, Safari since 17.2 and Firefox since 132. Browsers without support ignore the attribute, so it is safe to use as a progressive enhancement.
Related
- Parent: Resource Hints and Navigation Speed — the full set of hints.
- Optimizing LCP on Astro with Priority Hints — the hero image case.
- Lazy-Loading Images Without Hurting LCP — when lazy loading is the right tool.
- Early Hints (103) on Cloudflare — hints before the HTML.
- Breaking Up Long Tasks on Static Sites — the other half of INP.
Filed underHow-tos