How to Use fetchpriority for Scripts and fetch() Requests
This guide extends priority hints beyond the familiar LCP image, within Resource Hints & Early Hints and Advanced Caching Strategies & CDN Architecture. Browsers assign every request a priority based on its type and position: render-blocking CSS and fonts high, scripts in the head high, async scripts low, images low until they are known to be in the viewport, fetch() high by default. Those defaults are good guesses, but the browser cannot know that one async script drives your first render while another is analytics, or that a fetch() for the main content matters more than three fetch()s for recommendations.
The fetchpriority attribute (on <script>, <link>, <img>, <iframe>) and the priority option in fetch() let you say so. Raising the priority of critical requests and lowering non-critical ones changes the order in which they compete for bandwidth and connection slots — most valuable on congested mobile connections where everything cannot download at once.
Rapid Diagnosis
- Show the Priority column in the Network panel (right-click the header). Note priorities of requests that finish before LCP.
- Find critical async scripts. An async script that renders above-the-fold content but loads at Low priority behind images is a candidate.
- Find non-critical high-priority fetches. Analytics, recommendations and prefetch
fetch()calls default to High and compete with critical data. - Look at contention. On a throttled profile, if the critical request starts early but finishes late, it is competing with others.
Root Cause Analysis
1. Async scripts default to Low. A script that renders the hero via client-side rendering competes poorly with images.
2. fetch() defaults to High. Every data request — critical or not — competes equally.
3. Preloads at High for everything. Preloading late-needed resources pulls bandwidth from critical ones.
4. Late-discovered critical requests. Priority cannot fix discovery; a request that starts late still finishes late.
Step-by-Step Resolution
1. Raise critical async scripts
<script src="/assets/hero-render.7a1c.js" async fetchpriority="high"></script>
<script src="/assets/analytics.2b9d.js" async fetchpriority="low"></script>
<!-- trade-off: high-priority async scripts can delay images, including the LCP
image, if bandwidth is scarce. Raise only scripts the first render depends on. -->
2. Lower non-critical fetches
// Critical: main content (default High, or explicit).
const product = fetch(`/api/products/${id}`, { priority: 'high' }).then((r) => r.json());
// Non-critical: lower so they do not compete.
fetch(`/api/recommendations/${id}`, { priority: 'low' }).then(renderRecs);
navigator.sendBeacon?.('/rum', payload); // beacons are already low priority
// trade-off: 'low' requests may be delayed noticeably on congested connections.
// Do not lower anything the user is actively waiting for.
Expected outcome: the main content request finishes sooner under contention.
3. Lower late-needed preloads
<link rel="preload" href="/assets/below-fold-carousel.js" as="script" fetchpriority="low">
<!-- trade-off: a low-priority preload still starts early but yields bandwidth;
if the resource is needed soon after load, low priority can delay it. -->
4. Fix discovery first
Priority helps requests that are already in flight compete better. If a critical request starts late because it is discovered late, move it into the HTML or preload it first — see diagnosing LCP resource load delay.
Verification
In the Network panel, priorities should reflect your intent. On a throttled profile, critical requests should complete earlier relative to secondary ones. Measure LCP (for client-rendered content) or time-to-main-content with User Timing before and after; on congested connections the improvement can be several hundred milliseconds, on fast ones close to zero.
Worked Example: A Client-Rendered Product Page
A client-rendered product page issued six fetch() calls at startup — product, inventory, reviews, recommendations, personalised offers and an A/B config — all at High priority. On mobile, the product request finished at 1.4s because it shared bandwidth with the others. Marking reviews, recommendations and offers as priority: 'low' and raising the product request explicitly brought it to 0.8s; LCP p75 for the template fell by about 450ms. Total data loaded was unchanged; only the order improved.
How Priorities Interact With HTTP/2 and HTTP/3
Browser priorities are communicated to the server: HTTP/2 uses stream priorities (largely replaced by the simpler Extensible Priorities scheme), and HTTP/3 uses the Priority header and frames. Whether your server or CDN honours them determines how much fetchpriority changes delivery order on a shared connection. Most major CDNs implement prioritisation; some origins and proxies ignore it, in which case the browser's own scheduling (when to issue requests) still helps but in-flight bandwidth sharing does not change. Test on your real stack rather than assuming.
A Priority Plan for a Typical Page
Write down the intended order of the first second of loading, then make the hints express it. For a server-rendered product page it might be: HTML; critical CSS; the LCP image; the heading font; the hydration entry script; the product API refresh; everything else. Compare that plan with the Priority column and request start times in a throttled waterfall. Requests that should be early but start late need discovery fixes (preload, Early Hints); requests that start on time but finish late need priority changes; requests that are early but unimportant need lowering or deferral. Revisit the plan when templates change — a new carousel or widget quietly adds high-priority requests that reorder everything.
Common Mistakes
- Marking everything high. Priorities are relative; if everything is high, nothing is.
- Using fetchpriority to fix late discovery. It cannot start a request earlier.
- Lowering resources the user waits for. Users notice slow data more than slow analytics.
- Ignoring server support. Without server-side prioritisation, the effect on shared connections is smaller.
Edge Cases
Iframes. fetchpriority on iframes affects the iframe document's request priority, useful for deprioritising embeds.
Service workers. Requests made from a service worker carry their own priority; passing through event.request preserves it.
Safari support. Priority hints are supported in recent Chromium, Safari and Firefox versions; the attribute is ignored safely where unsupported.
Speculative loading. Prefetches and speculation rules already run at low priority; no hint needed.
FAQ
Is fetchpriority the same as preload?
No. Preload makes the browser start a request early; fetchpriority changes how a request competes once started. They combine well: preload the LCP image and give it fetchpriority="high".
Does fetchpriority help on fast connections?
Less. With ample bandwidth, requests do not compete much and order matters little. The biggest gains are on congested mobile networks.
Can I lower the priority of third-party scripts I do not control?
Only if you load them — add fetchpriority="low" to the script tag you write. Scripts injected by a tag manager inherit whatever the injecting code sets.
What priority does sendBeacon use?
Beacons are sent at low priority by design, which is why they are suitable for analytics.
Should fonts get fetchpriority?
Fonts are already high priority when discovered. Preloading the critical font is more useful than adjusting its priority.
How do I confirm the server honours priorities?
Compare a throttled waterfall with and without the hints on the real stack. If completion order changes, prioritisation is effective end to end.
Does fetchpriority change the order of script execution?
No. Execution order is governed by script type (defer scripts run in document order; async scripts run when they arrive). Priority only affects how quickly the bytes arrive, which can change when an async script happens to run.
Can a low-priority request be starved entirely?
Rarely on modern browsers — low-priority requests still proceed, just after higher-priority ones on contended connections. On very slow connections they can be delayed by seconds, which is acceptable for analytics and prefetches but not for anything visible.
Related
- Using fetchpriority to prioritize the LCP image — the most common use of the hint.
- Preload vs preconnect: when to use each — starting requests earlier.
- Diagnosing head-of-line blocking — how transport affects request ordering.