Cookie Consent by Free Privacy Policy Generator

Cloudflare Worker to automatically Lazy-load below-the-fold images

Here’s a lightweight Worker script that auto-adds loading="lazy" to images further down the page. It leaves the first couple untouched (default is 2) so hero or header images load immediately, then lazies the rest. It also skips any image that already has a loading attribute set.

It's using the browser's native lazy loading, so there's no background scripting or JavaScript involved. The Worker just rewrites the HTML on the edge and adds loading="lazy" to the right <img> tags before the page reaches the browser. Modern browsers take it from there. They spot the attribute and delay loading the image until it's about to come into view. Clean, fast, and handled entirely by the browser once the HTML lands.

Useful for quick performance wins! No layout shifts, no JavaScript overhead, just native lazy loading applied consistently at the edge. Adjustable based on your page structure, you could tweak it based on the page template, eg skip 4 images, etc.

Example:
Code:
<img src="/images/header.jpg">
<img src="/images/feature.jpg">
<img src="/images/gallery-1.jpg">

Becomes:
Code:
<img src="/images/header.jpg">
<img src="/images/feature.jpg">
<img src="/images/gallery-1.jpg" loading="lazy">

Here's the Worker script:
Code:
const ABOVE_THE_FOLD_IMAGE_COUNT = 2; // adjust based on your layout

export default {
  async fetch(request, env, ctx) {
    const response = await fetch(request);
    const contentType = response.headers.get("content-type") || "";

    if (!contentType.includes("text/html")) {
      return response;
    }

    const html = await response.text();

    let imageCount = 0;
    const modifiedHtml = html.replace(/<img([^>]*?)>/gi, (match, attributes) => {
      imageCount++;

      // Skip if loading attribute already exists
      if (/loading\s*=\s*["']?lazy["']?/i.test(attributes)) {
        return `<img${attributes}>`;
      }

      // Only add loading="lazy" to images after the defined threshold
      if (imageCount > ABOVE_THE_FOLD_IMAGE_COUNT) {
        return `<img${attributes} loading="lazy">`;
      }

      return `<img${attributes}>`;
    });

    return new Response(modifiedHtml, {
      status: response.status,
      headers: {
        'content-type': 'text/html; charset=UTF-8'
      }
    });
  }
};

What It Does:

  • Leaves the first couple of images untouched (you define how many).
  • Adds loading="lazy" to the rest.
  • Skips images that already have a loading attribute.
  • Works entirely on the edge,no client-side JS, no render blocking.
 
Last edited:
Back
Top