Lazy Loading Strategy for Landing Pages
The Goal: Defer, Don't Delete
Lazy loading means deferring the download of resources until they're actually needed — typically when an element scrolls near the viewport — rather than loading everything upfront. For long-scrolling landing pages packed with testimonials, feature grids, video embeds, and third-party widgets, this is one of the highest-leverage performance techniques available, because it directly reduces initial payload and main-thread work without removing any content from the page.
Native Lazy Loading for Images and Iframes
Modern browsers support loading="lazy" natively on <img> and <iframe> with no JavaScript required. The browser uses its own heuristics (roughly a viewport-distance threshold) to start fetching slightly before the element is visible, avoiding a visible pop-in. This covers the majority of landing-page lazy-loading needs — embedded YouTube videos, below-the-fold testimonial photos, and comparison tables — with zero added script weight. The only caveat: never apply it to the LCP candidate, which should load eagerly (see the image optimization lesson).
import { useEffect, useRef, useState } from "react";
// For content that isn't a plain <img>/<iframe> — e.g. a heavy
// chart library, a map embed, or a third-party review widget —
// use IntersectionObserver to defer mounting entirely.
export function LazySection({ children }: { children: React.ReactNode }) {
const ref = useRef<HTMLDivElement>(null);
const [visible, setVisible] = useState(false);
useEffect(() => {
const el = ref.current;
if (!el) return;
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setVisible(true);
observer.disconnect();
}
},
{ rootMargin: "200px 0px" } // start mounting 200px before entering viewport
);
observer.observe(el);
return () => observer.disconnect();
}, []);
return <div ref={ref}>{visible ? children : <div style={{ minHeight: 400 }} />}</div>;
}Reserve Layout Space to Protect CLS
width/height on images, or a min-height placeholder for dynamically mounted components, so the surrounding content doesn't jump when the deferred element finally loads.Lazy Loading Third-Party Marketing Widgets
The biggest wins on marketing pages often come from deferring the tags marketers themselves added, not just content. Chat widgets (Intercom, Drift), review widgets (Trustpilot, Yotpo), and heatmap tools (Hotjar, Clarity) typically don't need to exist until the user has scrolled or spent a few seconds on the page. In GTM, this is done with a Custom Event or Timer trigger instead of the default 'Page View' trigger — e.g., fire the chat widget tag on a Timer trigger set to 4000ms, or on a custom event dispatched by a scroll-depth trigger.
// GTM Custom HTML tag, fired on a Timer trigger (e.g. 3s after page load)
// instead of on page load, to defer a non-critical chat widget.
(function () {
if (window.__chatWidgetLoaded) return;
window.__chatWidgetLoaded = true;
var script = document.createElement("script");
script.src = "https://widget.examplechat.com/loader.js";
script.async = true;
document.body.appendChild(script);
})();When Lazy Loading Hurts Conversion
Lazy loading isn't free. Two failure modes recur on marketing pages:
- Lazy-loaded forms or CTAs: if the primary conversion element itself is deferred behind a mount delay, you've traded page speed for a slower path to conversion — a bad trade. Never lazy-load the fold's primary CTA.
- SEO content visibility: search crawlers render JavaScript but don't always wait for IntersectionObserver-triggered mounts the way a real scrolling user does. Below-the-fold SEO copy that depends on scroll-triggered lazy mounting can be invisible to crawlers that don't scroll. Prefer native loading="lazy" (which crawlers handle fine) over JS-mounted lazy content for anything SEO-relevant.
Test Lazy-Loaded Analytics Separately
What's Next?
Lazy loading reduces what the browser downloads; the next lever is reducing how far that download has to travel in the first place.
I build these systems professionally.
Whether it's a RAG pipeline, analytics migration, or AI workflow — let's talk.