How to check if images are lazy loaded
Fetch the served HTML and count the <img> tags against the loading="lazy" attributes, then confirm in the browser that images below the fold hold their requests until you scroll. The markup count and the rendered count differ whenever script inserts images after the load.
Why check this
Lazy loading is a two-sided setting, and both sides break releases. Missing it on a long page pulls dozens of images into the first load. Applying it to the image at the top of the viewport delays the largest paint instead. Run this check after any template change that touches image markup, and before sign-off on any page with a gallery, a feed or a long article.
Prerequisites
- curl 8 or later, or Node 20 or later. See the curl manual.
- Chrome with DevTools for the rendered check. Record your build from
chrome://version. - The attribute reference on MDN, the loading attribute.
Steps
- Step 1.
Count the image tags in the served markup and how many of them carry the attribute.
curl -s https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS | grep -o '<img[^>]*>' | awk '{n++; if ($0 ~ /loading="lazy"/) lazy++} END {printf "img %d\nlazy %d\nmissing %d\n", n, lazy, n-lazy}'img 4 lazy 4 missing 0This is the pre-filter. It answers one question: does the server send the attribute. It cannot tell you whether the browser honoured it.
- Step 2.
List the tags one by one, so a single missing attribute names its own file.
node -e "const html = await (await fetch('https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS')).text(); const imgs = html.match(/<img[^>]*>/g) || []; for (const tag of imgs) { const loading = (tag.match(/loading=\"([^\"]+)\"/) || [])[1] || 'NONE'; console.log(loading.padEnd(6), (tag.match(/src=\"[^\"]*\/([^\"\/]+)\"/) || [])[1]); } console.log('img', imgs.length, '| lazy', imgs.filter(t => /loading=\"lazy\"/.test(t)).length);"lazy fetching-page-cors.svg lazy simple-request.svg lazy preflight-correct.svg lazy include-credentials.svg img 4 | lazy 4 - Step 3.
Open the URL in Chrome, press F12 and read the same counts from the rendered document rather than from the markup.
<img> elements 4 loading="lazy" 4 no loading attribute 0Both counts agree on this page. On a page that builds its gallery in script, they will not, and the rendered count is the one that matters.
- Step 4.
Confirm the deferral is real. Open the Network panel, filter to Img, tick Disable cache, reload without scrolling, and count the image requests. Scroll to the bottom and count again. Images that only appear in the second count are the ones being deferred.
How to read the result
| What you see | What it means | What to do |
| --- | --- | --- |
| missing 0 in step 1 | Every image in the served markup carries the attribute | Check step 4 next. Presence is not behaviour. |
| missing above zero | Some images load with the first request | Confirm they are above the fold before filing anything. |
| The markup count is below the DOM count | Script adds images after the load | Test with the DOM count, and check how the script sets the attribute. |
| Every image requested before you scroll | Nothing is being deferred | Look for a script that rewrites the attribute, or a viewport tall enough to contain them all. |
| The top image is lazy | The largest paint waits for layout before its fetch starts | Remove the attribute from that one image. |
Common mistakes
What to check next
- How to check LCP of a page: a lazy attribute on the largest element shows up as load delay.
- How to check CLS: a deferred image with no reserved box shifts the content when it arrives.
- How to test core web vitals: the gate both of those metrics feed.
- How to check render blocking resources: the other half of what delays a first paint.
- How to check HTTP response headers with curl: confirm the document you scanned is the one the server sends to a browser.
FAQ
How to check if images are lazy loaded without DevTools?
Step 1 is the answer for native lazy loading. It reads the attribute straight from the served HTML and needs no browser. What it cannot show is whether the browser deferred the request, which needs the Network panel in step 4.
Should every image be lazy loaded?
No. Images inside the first viewport should load with the page, and the largest of them decides LCP. Apply the attribute from the first image below the fold onward.
How do I tell native lazy loading from a script-based one?
Native lazy loading is the loading="lazy" attribute in the markup. A script-based one usually leaves src empty or pointing at a placeholder and keeps the real URL in data-src. The two behave differently with JavaScript disabled.
Does lazy loading reduce page weight?
It reduces the weight of the first load, not the total. A reader who scrolls to the end downloads the same bytes. The gain is in what the first paint has to compete with.
Verified
The rendered counts in step 3 come from one Chrome DevTools capture of https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS on 2026-09-11, on one machine. The two command steps were run against the same URL on the same day. Read your own Chrome build from chrome://version and record it with your own numbers.
Verified by Maks Vernycurl 8.21.0node 22.23.2
Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.
Related on this site
basic6 minpublished updated Maks Verny