Why Does Chrome DevTools Full-Page Capture Miss Lazy-Loaded Images?
A full-page screenshot captures page dimensions, not every deferred image. Learn how to trigger lazy loading, verify requests, and capture the finished page.
A Chrome DevTools full-page screenshot can include the entire document while still showing blank spaces or placeholders where lazy-loaded images have not rendered. Capturing beyond the viewport and causing off-screen content to load are separate steps: Chrome’s full-size capture covers content outside the visible viewport, while an image with loading="lazy" is fetched when the browser judges it close enough to the viewport. A screenshot does not guarantee that every deferred image request has happened.
To get a complete capture, scroll through the page to trigger viewport-based loading, wait for the relevant image requests and rendering to finish, then capture the full page again. If the page uses custom JavaScript loading, scrolling may need to trigger the site’s own behavior too.
1. Capture the full page in DevTools
- Open the target page in Chrome.
- Open DevTools and switch to Device Mode.
- Open the Device Mode More options menu and select Capture a full size screenshot. Chrome documents this command as capturing the whole page, including content outside the visible viewport (Chrome Device Mode documentation).
This command handles page extent. It does not promise that every image outside the viewport was fetched first. If images are missing, use the workflow below before repeating the capture.
2. Trigger lazy loading and capture again
- Return to the page and scroll down in sections, giving each section time to load before continuing. Scrolling brings viewport-triggered images near the visible area; the browser or the site can then start their requests.
- At the bottom, pause for images to finish loading and render. For long pages, scroll back up and check sections that were still showing placeholders.
- Inspect any remaining suspect image in the Console using the snippet below.
- Check the Network panel for the image request and whether it completed or failed.
- Return to the top if the capture workflow or site expects that, then use Capture a full size screenshot again.
For native lazy loading, loading="lazy" defers fetching until the browser-calculated distance from the viewport. The page’s load event is not an all-images-ready signal: lazy images can still be pending after it fires. See MDN’s references for the image element and its loading attribute and lazy loading behavior.
3. Inspect an image and its request
Select an image in the Elements panel so it is available as $0, then run:
({
loading: $0.loading,
src: $0.getAttribute('src'),
currentSrc: $0.currentSrc,
complete: $0.complete,
naturalWidth: $0.naturalWidth,
naturalHeight: $0.naturalHeight
})
loading helps identify native lazy loading. src is the markup attribute, while currentSrc shows the selected resource, including responsive-image selection. A Boolean complete of false means the image has not finished loading; true alone does not guarantee that it loaded successfully. Check naturalWidth and naturalHeight as well: zero dimensions are a clue that no usable image decoded.
To list images that are not complete, run:
[...document.images]
.filter(img => !img.complete)
.map(img => ({
loading: img.loading,
src: img.getAttribute('src'),
currentSrc: img.currentSrc,
complete: img.complete
}))
This is a snapshot of the current DOM state. It does not trigger lazy loading, and it only inspects <img> elements. CSS background images and content created later by scripts need separate inspection.
Use Network screenshots to diagnose timing
In DevTools, open Network, enable Capture screenshots, then reload. The panel can correlate what the page looked like with network activity at that point, helping distinguish an image request that never started from one that started and failed (Chrome Network features reference). For behavior that appears only after scrolling or another interaction, record the page in the Performance panel and look for the interaction and resulting activity.
4. Understand the common causes
| Cause | What you may see | What to do |
|---|---|---|
| Native lazy loading | The element has loading="lazy"; its request may not begin until it approaches the viewport. |
Scroll the image into or near view, then wait for its request and rendering. |
| Custom lazy-loading script | The real URL may be stored in a data attribute, or assigned only after an intersection or scroll callback. | Scroll through the page to trigger the site’s behavior. Inspect the element’s attributes and watch the Network panel for a request. |
| Request failure or delay | A request appears in Network but fails, remains pending, or takes longer than the capture wait. | Inspect its status and timing. Resolve the network or server issue, or wait for the request before capturing. |
| Image decoded but not visibly present | The image reports completion, but the screenshot still looks empty or shows a placeholder. | Check its natural dimensions, computed styles, overlays, and whether the page swaps from a placeholder after another script runs. |
Not an <img> element |
The visual is missing from the image list. | Inspect the relevant element for a CSS background image, pseudo-element, canvas, or script-generated content. |
Native lazy loading is deferred only when JavaScript is enabled, according to MDN’s image reference. A site can also implement its own loading logic, so the exact trigger depends on that page’s code. Avoid treating one capture as proof that Chrome has a universal full-page screenshot defect.
5. Troubleshooting
| Symptom | Likely explanation | Fix |
|---|---|---|
| Full-height screenshot has empty image slots | The capture included the document area, but off-screen images had not loaded. | Scroll through the page, wait for requests and rendering, then capture again. |
The page fired load, but images are still missing |
Lazy images are not necessarily part of the eager-resource basis for the load event. |
Check the specific image’s complete, dimensions, and Network request instead of relying on the event. |
complete is false |
The image has not finished loading; this value alone does not explain why. | Check whether a request started, whether it is pending or failed, and whether the lazy-loading trigger occurred. |
complete is true but the image is blank |
The resource may have failed, decoded to unusable content, or be hidden or covered. | Check natural dimensions, request status, computed styles, and any placeholder-swapping script. |
| Scrolling does not load the image | The site may use another trigger, a custom script, or a non-image rendering technique. | Inspect the element and page behavior; use Network and Performance recordings to see whether interaction produces a request or DOM change. |
| The image request failed | The capture cannot include an image the browser did not retrieve successfully. | Open the request in Network and investigate its status, URL, and timing; retry only after the underlying failure is resolved. |
6. What each capture method solves
| Method | Useful for | Does not establish by itself |
|---|---|---|
| DevTools full-size screenshot | Capturing content beyond the visible viewport. | That every deferred image request has occurred and rendered. |
| Scrolling and waiting | Triggering viewport-based native or custom loading and allowing time for requests. | That every request succeeded; check the image and Network panel. |
| Network screenshots | Correlating visible page state with requests while the page loads. | A full-page capture or a guarantee that a site-specific interaction happened. |
| Performance recording | Investigating runtime activity around scrolling and other triggers. | That a capture will include content which never loaded or rendered. |
Chrome’s documentation describes the full-size command and Network screenshots as separate tools for page extent and load-time diagnosis. A historical Chrome 89 note discusses full-node capture behavior, but it is not a guarantee for every current page or Chrome version (Chrome 89 DevTools notes).
7. Reliability, time, and capture cost
For a one-off page, manually scrolling and checking the relevant requests is usually the clearest way to diagnose the missing content. It is also sensitive to page behavior: target markup, CSS, JavaScript, network state, viewport, and Chrome version can all affect what has rendered at capture time.
For a repeatable capture workflow, define what “ready” means for the page: for example, the target images have loaded, a known selector is visible, or the site’s scroll-triggered content has appeared. A generic wait for the window load event is insufficient for lazy images. DevTools’ manual workflow has no API-per-request price, but it does require developer time and repeated inspection when pages behave differently.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. Its API can capture a URL in one request, with options including full-page capture with lazy images loaded and waiting for a selector, delay, or network idle. See the API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed; response headers say whether a result was billed. An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for 1,000 free screenshots a month with no card.
FAQ
Does a full-page screenshot scroll the page for me?
Do not assume it does. Full-size capture covers content beyond the viewport; scrolling and waiting are separate steps that can trigger lazy loading.
Does the page’s load event mean all images are ready?
No. Lazy-loaded images can remain pending. Inspect the image and its request directly.
Can I tell whether an image failed using complete?
Not by itself. It indicates whether loading has completed, not whether a usable image was successfully retrieved and displayed. Check dimensions and the Network request too.
Why might an image still be absent from document.images?
It may be a CSS background, canvas content, or an element created by script. Inspect the rendered element and its styles.


