How to Use LQIP and Lazy Loading to Improve Page Performance
Use lazy loading for below-the-fold images and tiny LQIPs for visual continuity. Keep the likely LCP image eager, then measure the results.
Use native lazy loading for images below the initial viewport, and keep the likely Largest Contentful Paint (LCP) image eager. Add a tiny low-quality image placeholder (LQIP) when a blurred preview improves the transition while the full image loads. These techniques do different jobs: lazy loading defers the full image request; an LQIP changes what the reader sees during that request. Neither guarantees a faster LCP, so measure the page before and after.
1. Decide which images should load immediately
Check the page at mobile and desktop sizes. Identify which images appear in the initial viewport and which element is the actual or likely LCP element. The answer can differ by viewport.
- Initially visible hero or likely LCP image: do not add
loading="lazy". Keep it discoverable in the initial HTML. If measurement shows it needs help, evaluate fetch priority or preload. - Content images below the fold: use native
loading="lazy". The browser can defer fetching them until they are closer to view, reducing competition for bandwidth from images a visitor may never see.
Browser lazy loading uses layout to determine an image’s position. That can delay a visible image while styles load and layout becomes known. Avoid applying lazy loading as a blanket rule in a shared component or CMS.
2. Add native lazy loading to below-the-fold images
This is runnable HTML for an image that is clearly below the initial viewport:
<img
src="/images/article-example.webp"
alt="A developer reviewing a page on a laptop"
width="800"
height="533"
loading="lazy"
>
Keep the width and height (or an equivalent aspect ratio) so the browser can reserve space before the image arrives. This helps avoid layout shifts. Use meaningful alternative text when the image conveys information; use an empty alt="" for purely decorative images.
For the hero image, leave out loading="lazy":
<img
src="/images/hero.webp"
alt="A descriptive alternative for the hero image"
width="1600"
height="900"
>
3. Add an LQIP when a preview helps
An LQIP is a tiny, low-detail image enlarged and often blurred as a temporary preview. It can make the transition feel smoother, but it does not change when the browser downloads the full-size image. Keep the placeholder payload small: Next.js recommends a source image of 10 pixels or less for its blur placeholder approach and cautions that large blur data URLs can hurt performance.
Next.js Image example
For a remote or dynamic image, provide a small blur data URL. The following component expects smallBlurDataUrl to be a valid data URL generated from a tiny image. Use loading="lazy" only for a below-the-fold image.
import Image from 'next/image';
export function ArticleImage({ photo, smallBlurDataUrl }) {
return (
<Image
src={photo}
alt="A descriptive alternative"
width={1200}
height={800}
placeholder="blur"
blurDataURL={smallBlurDataUrl}
loading="lazy"
/>
);
}
For a hero or likely LCP image, remove loading="lazy". Supported static imports can have a generated blur URL automatically (animated images are an exception). Dynamic and remote sources need a supplied blur value. Remote images also need dimensions because the build process cannot inspect the remote file.
Check the Image component docs for the installed Next.js version. The current App Router docs say loading defaults to lazy; Next.js 16 deprecates priority in favor of preload. Older examples may use different props.
Plain HTML placeholder option
For plain HTML, a tiny inline preview can be layered behind the final image. This example assumes the parent reserves the image’s aspect ratio and that the tiny data URL is available. Remove the temporary background or placeholder when the full image loads. A framework image component is usually simpler because it handles this transition for you.
<div style="aspect-ratio: 3 / 2; background: #eee">
<img
src="/images/article-example.webp"
alt="A developer reviewing a page on a laptop"
width="1200"
height="800"
loading="lazy"
style="width:100%;height:100%;object-fit:cover"
>
</div>
This HTML reserves space and lazy-loads the image; it does not itself implement a blur data URL. Add a tiny preview only if it improves the experience and its encoded payload is worth the cost. Avoid embedding a large base64 image in markup.
4. Help the browser discover a critical image
First ensure the likely LCP image is present and discoverable in the initial markup. If it is discoverable but competing requests delay it, test fetchpriority="high" on that image:
<img
src="/images/hero.webp"
alt="A descriptive alternative"
width="1600"
height="900"
fetchpriority="high"
>
Fetch Priority is a hint, not a guarantee. Use it sparingly and verify its effect; raising one request’s priority can affect other resources. A preload can help when a critical image is otherwise discovered late, such as an image referenced from CSS. Preload and fetch priority address different things: preload helps expose a resource early, while priority influences its relative importance after it is fetched. Test both against the page rather than adding them by default.
5. Measure the result
- Record a baseline for the same page, viewport, device class, and test conditions.
- Check which element is LCP and when its image request begins.
- Confirm below-the-fold image requests are deferred and note transferred image bytes and request counts.
- Compare after the change, including mobile and desktop field data where available. Evaluate LCP at the 75th percentile separately for each; web.dev defines a good LCP as 2.5 seconds or less.
- Check layout stability and the actual loaded image, not just the appearance of the placeholder.
An LQIP can improve perceived continuity without making the final LCP happen earlier. Lazy loading can reduce unnecessary image work, but the result depends on image placement, browser behavior, network conditions, and the rest of the page. web.dev reported one Fetch Priority experiment on Google Flights that changed LCP from 2.6 to 1.9 seconds; treat that as one site’s result, not an expected gain for other pages.
6. Troubleshoot common problems
| Symptom | Likely cause | Fix |
|---|---|---|
| Hero image or LCP is late | The visible image has loading="lazy", or the browser discovers it late. |
Remove lazy loading from the likely LCP image. Keep it in initial markup; test fetch priority or preload if discovery or priority remains an issue. |
| Images load late while scrolling | Images are marked lazy even though they are near the viewport, or the browser has not established their layout position. | Confirm reserved dimensions and inspect the affected viewport. Do not lazy-load images that are initially visible or too close to be safely deferred. |
| The placeholder does not appear in Next.js | A dynamic or remote image has no blurDataURL, or the source is not a supported static import. |
Supply a small valid blur data URL and the required dimensions for a remote image. Check the installed Next.js docs and source handling. |
| Markup or transferred bytes increased | The placeholder is too large, often because a high-resolution image was encoded as a data URL. | Generate a tiny preview, around 10 pixels or less for the Next.js blur pattern, and compare the payload cost with the visual benefit. |
| The page feels smoother but LCP did not change | The placeholder affects the interim appearance, not the full image’s request schedule or final render time. | Keep the LQIP only if the visual transition is worth its cost. Improve LCP by addressing discovery, priority, image size, or other measured bottlenecks. |
| Adding fetch priority has no visible effect | It is a hint, and another bottleneck may dominate. | Verify the request priority and start time in a browser trace. Test preload only when discovery is late; avoid stacking hints without evidence. |
7. Reliability, performance, and cost considerations
- Reliability: native lazy loading leaves scheduling to the browser. Layout dimensions help prevent content jumps; test responsive layouts because image roles shift between mobile and desktop.
- Performance: lazy loading can reduce initial image transfers, while LQIP adds placeholder data. Count the placeholder bytes as part of the page’s cost.
- Priority: priority controls are hints. Confirm their effect on real requests and preserve bandwidth for resources that matter to the initial view.
- Cost: fewer unnecessary image downloads can reduce data transfer, but the actual savings depend on which images users reach and how the page serves them. No universal performance gain follows from adding these attributes.
Or skip the browser setup
If you need screenshots to inspect a page’s rendered state, ScreenshotNeo is a website screenshot API and MCP server. It does not replace implementing or measuring image loading in your own app, but it can simplify capturing pages during development. See the API documentation.
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, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up free and capture your first screenshots.
FAQ
Should I lazy-load the hero image?
No, if it is initially visible or likely to be the LCP image. Keep it eager and discoverable, then measure whether it needs priority help.
Does an LQIP make the full image load faster?
No. It supplies an interim visual while the full image loads. It may improve perceived continuity, but it does not accelerate the full image request by itself.
What is a good LCP target?
Web.dev’s good threshold is 2.5 seconds or less at the 75th percentile, evaluated separately for mobile and desktop.
Do I need both lazy loading and a placeholder?
No. They solve separate problems and can be used together: lazy loading controls when the full image is requested; a placeholder controls what appears during loading.


