You're Letting the Browser Guess. fetchpriority Fixes That.
Your hero image is losing a bandwidth fight against a web font and a chat-widget script — fetchpriority tells the browser which request actually matters first.

Your Lighthouse report says 2.8 seconds to Largest Contentful Paint. The hero image is 40KB, served from a CDN, and the Network tab shows it downloading in 200ms flat once it starts.
So why does it start 1.6 seconds after the page asked for it?
Scroll the waterfall and there they are, ahead of it: a web font, and a <script> tag for a chat widget nobody's clicked yet. Nothing is technically broken. The browser just decided, on its own, that both of those matter more than the image your user is staring at.
The fix is one HTML attribute. Realizing the browser had an opinion about my image at all is what took the other three hours.
The first instinct is to reach for <link rel="preload">:
This genuinely helps — it tells the browser about the image before the parser would otherwise discover it, which is the right move if your hero image is buried in a background-image or loaded by JS. But preload changes when the browser finds out about a request. It says nothing about how that request should compete once it's sitting in the queue next to everything else.
Open your DevTools Network panel right now on any image-heavy page, right-click the column header, and turn on Priority. Find an above-the-fold image. If it says Low or Medium, you've found the bug before reading the next paragraph — and preloading it wouldn't have changed that column at all.
Quick guess before I explain it: why would a browser ever decide a visible hero image is less important than a font or a script it hasn't even rendered text with yet?
Chromium, Firefox, and Safari all ship an internal resource-priority scheduler that ranks every request before it competes for a connection. The exact ranking is implementation-specific — Chromium's DevTools even exposes it as a column precisely because it isn't something you can read from the HTML — but the shape is consistent across engines: things that block rendering (CSS, @font-face sources once referenced by visible text, render-blocking scripts in <head>) get bumped up. Images, by default, don't. The browser can't know your <img> is the LCP element just by looking at the markup — it's guessing, and on real pages with real markup order, it guesses wrong often enough to matter.
fetchpriority exists so you stop leaving that guess to chance. It's not a new loading mechanism — it's a direct hint to the same scheduler that was already going to rank your request, on <img>, <link>, <script>, and the priority option on fetch() itself:
And it cuts the other way too — you can tell the browser something matters less than its default guess, which is the half of this feature most people skip:
Notice loading="lazy" and fetchpriority="low" sitting on the same <img>, doing two different jobs: loading decides when the browser even starts caring about this image (near-viewport, not before); fetchpriority decides how it competes for bandwidth once it does start. People reach for one when they mean the other, then wonder why "lazy-loading everything" didn't fix their LCP — lazy-loading the wrong element doesn't touch priority, and deprioritizing the right one doesn't delay its start. They're levers on different axes.
Support isn't a gamble here, either: all three major engines ship fetchpriority now, and a browser that doesn't recognize it just ignores it, the way HTML always treats an attribute it doesn't know. There's no feature check to write and no fallback to design — it's additive from day one.
Set fetchpriority="high" on the real LCP candidate and the effect isn't theoretical — it's a different value in that Priority column in DevTools, immediately, and a different position in the waterfall relative to whatever used to beat it there. The playground below models a simplified version of exactly this: two connections, three requests — a font, a script, and a hero image — and one dial on the image. Run it both ways and watch the image's finish time roughly halve, and the chat widget's finish time get pushed back to pay for it.
That tradeoff is the honest part people leave out of posts like this. Priority is zero-sum on a connection that can only do so much at once. Marking your hero image high doesn't manufacture bandwidth — it takes some back from whatever the browser was giving it to a script your user probably hasn't needed yet. That's usually the right trade. It's still a trade, and it's one you're now making on purpose instead of by accident.
Runs right in your browser — poke at it and watch the concept react live.
The chat widget script was never the villain. It's just a thing that can wait, sitting in a queue that didn't know it could wait, next to an image that couldn't. fetchpriority doesn't add a request or remove one — it tells the browser the one thing it was never in a position to know on its own: which pixel your user is actually staring at.
One line. No library, no build step, no useEffect to clean up.
Go open your Network tab on something you shipped. Add the Priority column. If your LCP image says Low, you already know what's next to it — a font, a script, something that doesn't need to win. What's it racing against on your site? I'd genuinely like to know what you find.
Think it clicked? Take the 7-question quiz →
Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.
- The Modal Was Open. So Was Everything Behind It.
- Shadow DOM Needed JavaScript to Exist. Now It Doesn't.
- JSON.stringify Is Quietly Deleting Your File Uploads
🚀 Want more like this? Every guide, playground, and quiz lives on bestpractic.org — open it and sign up free so the next one finds you.
Thanks for reading! Let's stay connected:
- ⭐ GitHub — follow me and star the projects: github.com/parsajiravand
- 💬 Discord — join the frontend best-practices community: discord.gg/d9KRhuAwQ
- 📸 Instagram — frontend best practices, daily: @bestpractice___
Keep reading
One post a day, in your inbox
Each one with a runnable playground and a quiz. No pitch, no digest, unsubscribe in one click.
0 comments
Sign in to join the discussion, like comments, and save articles for later.