A Manifest V3 browser extension that visualises a page's network request waterfall, annotates every resource with its computed / estimated fetch priority, and highlights the loading problems that hurt real-world performance — render-blocking resources and late-discovered critical assets.
No build step, no npm dependencies, no telemetry. Just load it unpacked.
Waterfall Inspector gives you two ways to inspect how a page loads:
- A DevTools panel ("Waterfall") that draws the full request timeline from the browser's own network data, with per-phase timing bars and a priority badge on every row.
- An in-page overlay — a compact, draggable panel injected into the current tab straight from the toolbar popup, so you can spot problems without even opening DevTools.
Both surfaces label priority clearly as estimated wherever the browser's real internal value is not available to them, and both flag the same classes of issue.
DevTools panel (the "Waterfall" tab). A toolbar with a URL filter, a resource-type filter, a sort control (by start time, priority, size or duration), a Copy report button and Clear. Below it: a row of summary stats (requests, transferred bytes, render-blocking count, third-party origins, largest and slowest resource), a findings area, then the request table. Each row shows the file name, type, a colour-coded priority badge, size, total time, and a segmented waterfall bar (blocked, DNS, connect, TLS, TTFB, download). Render-blocking rows carry a deep-red edge; late-discovered critical rows carry a copper edge. A legend maps each colour to a timing phase.
In-page overlay. A small olive/gold panel pinned to the top-right of the page. A draggable header (with collapse and close buttons), four summary chips, a findings list, and a scrollable set of rows — each with a name, an estimated priority badge, transferred size, and a mini waterfall bar. It lives inside a Shadow DOM, so the host page's CSS can neither style it nor be styled by it.
This extension is distributed as source you load yourself.
Chrome / Edge / Brave (and other Chromium browsers):
- Open the extensions page: type
chrome://extensions(oredge://extensions) into the address bar and press Enter. - Turn on Developer mode (toggle in the top-right corner).
- Click Load unpacked.
- Select this project's
waterfall-inspectorfolder (the one containingmanifest.json). - Pin the extension from the puzzle-piece toolbar menu if you want quick access.
To see the DevTools panel, open DevTools (F12, or Cmd+Opt+I on macOS) on any page and choose the Waterfall tab. Reload the page to capture its waterfall.
Firefox: Firefox supports MV3 but uses browser.* APIs and a slightly
different DevTools model. This build targets Chromium. To try it in Firefox,
load it as a temporary add-on from the debugging page (about:debugging), and
expect the DevTools panel behaviour to differ; the popup and overlay rely on the
chrome.* namespace that Firefox aliases but does not fully match for
devtools.panels. Chromium browsers are the supported target.
The browser's real internal scheduling priority is not exposed to page
JavaScript. So the overlay (and the DevTools panel, when the browser value is
missing) estimates it from documented signals: the resource's initiator /
element type, whether it is render-blocking, its fetchpriority attribute, a
preload's as, loading="lazy", and whether it looks like the Largest
Contentful Paint candidate.
In the DevTools panel, when the browser reports a priority in the HAR data
(_priority), that value is used directly and the row is not marked as
estimated.
The heuristic mirrors Blink's rough defaults:
| Resource (initiatorType / element) | Estimated priority |
|---|---|
| Main document / navigation | Highest |
CSS <link rel=stylesheet> in <head> (render-blocking) |
Highest |
CSS that is non-blocking, media-scoped or loaded late |
Medium |
Font (as=font, .woff2, CSS-loaded) |
High |
Blocking <script> in <head> (no async/defer) |
High |
<script> with async / defer / injected |
Low |
| Image that is the LCP candidate / above the fold | High |
| Image, in-flow default | Low |
Image with loading="lazy" / offscreen |
Lowest |
XHR / fetch() |
High |
| Beacon / ping | Lowest |
| Audio / video | Low |
| Anything else | Medium |
Then Priority Hints nudge the result: fetchpriority="high" moves it up one
step, fetchpriority="low" moves it down one step. The five levels — Highest,
High, Medium, Low, Lowest — are colour-coded from clay/copper through gold to
moss/sage. The full logic and its inline references live in
lib/priority.js.
- Waterfall bars with distinct colours for each timing phase: blocked/stalled, DNS, connection, TLS, waiting (TTFB) and content download.
- A colour-coded priority badge per row (Highest / High / Medium / Low / Lowest), with a tooltip explaining why that level was chosen.
- Highlights render-blocking resources: synchronous
<script>in<head>withoutasync/defer, and active non-print<link rel=stylesheet>in<head>. - Highlights late-discovered critical assets: CSS, fonts and large images fetched well after the page started — with a suggestion to preload them.
- Flags lazy-loaded images that are above the fold (an LCP risk).
- Summary stats: total requests, total transferred bytes, render-blocking count, third-party origin count, largest resource and slowest resource.
- Sortable and filterable request list (by priority, type, size, time, or a URL substring) in the DevTools panel.
- A Copy report button that copies a plain-text summary to the clipboard.
- Draggable, collapsible, dismissable overlay that will not break the host page.
The extension requests the minimum it needs, and only acts on the tab you are looking at when you ask it to:
activeTab— grants temporary access to the current tab only after you invoke the extension (open the popup or use its controls). This is what lets the popup read the page's stats and inject the overlay, without a broad host-permission grant.scripting— lets the popup/background inject the overlay and the small stats collector on demand. Nothing is injected until you click a button.web_accessible_resources— exposes onlycontent/overlay.cssso the overlay can load its own scoped stylesheet into its Shadow DOM.
There is no host_permissions, no tabs permission for browsing history,
and no background network access. The extension reads only local performance
data (Resource Timing, HAR entries from your own DevTools session, and the
page's DOM) and renders it locally. It sends nothing anywhere — no
analytics, no remote logging, no external requests.
- DevTools panel —
devtools.jsregisters the "Waterfall" panel;panel.jslistens tochrome.devtools.network.onRequestFinished, pulls the HAR entries (including the browser-reported_prioritywhen present), normalises them, runs the analysis and renders the table. It resets when the inspected page navigates. - In-page overlay — the popup (
popup.js) asks the background service worker (background.js) to injectlib/format.js,lib/priority.jsandcontent/overlay.jsinto the active tab. The overlay readsperformance.getEntriesByType('resource')plus aPerformanceObserver(including a Largest Contentful Paint observer), matches each request to its DOM element to learnfetchpriority/loading/ render-blocking status, estimates priorities, and paints itself inside a Shadow DOM. Re-injecting is idempotent — it simply toggles the existing overlay. - Shared libraries —
lib/priority.js(the heuristic),lib/waterfall.js(normalisation + rendering helpers) andlib/format.js(byte/ms formatting) are plain scripts shared by both surfaces.
- Estimated vs. real priority. Outside the DevTools/HAR path, the priority shown is a computed estimate, not the browser's actual internal value, which pages cannot read. Treat it as a well-informed approximation.
- Cross-origin resources without a
Timing-Allow-Originheader expose only coarse timing, so their waterfall bar collapses to a single "download" segment. - Render-blocking detection in the DevTools panel is inferred from HAR initiator data (async/defer is not present in HAR), so it is an estimate there too; the overlay reads the live DOM and is more precise.
- LCP-candidate and above-the-fold checks reflect the page state at the moment the overlay renders.
If you want to go deeper on the concepts this tool surfaces:
- Network waterfall anatomy & timing metrics
- Decoding the Chrome DevTools network waterfall
- Render-blocking resource identification
- The
fetchpriorityattribute & Priority Hints - Understanding browser resource priority queues
Contributions are welcome. Because there is no build step, the workflow is simple:
- Edit the source directly.
- Run
node --checkon any JavaScript file you touch, and confirmmanifest.jsonstill parses as valid JSON. - Reload the unpacked extension from the browser's extensions page and verify both the DevTools panel and the overlay.
- If you change the icons, regenerate them with
node icons/generate-icons.js.
Keep the code vanilla (no dependencies), keep the UI accessible, and keep the priority heuristic documented.
Released under the MIT License. Copyright (c) 2026 Network Priority.
Built alongside network-priority.com.