Eliminating Client-Side Flicker with Netlify Edge Functions
Stop the 'flash of unstyled content' in your A/B tests. Learn how to use Netlify Edge Functions and HTMLRewriter to personalize static pages at the CDN level.
30 Aug 2026, 08:07 UTC

The Problem: The "Flash of Unstyled Content" in Personalization
When you implement A/B tests or geo-targeted content using client-side JavaScript, users often see a "flicker." The browser renders the default page, the script executes, and then the content suddenly jumps or changes. This happens because the decision logic occurs after the HTML has already reached the browser.
To fix this, the decision must happen before the HTML is sent. Netlify Edge Functions allow you to intercept the request at the CDN node, make a decision based on cookies or geolocation, and modify the response in flight.
The Thesis
By shifting personalization logic from the browser to a Deno-based Edge Function, you can serve a tailored version of a static page with zero client-side flicker and minimal latency, keeping your origin build completely static.
How Edge Functions Intercept Requests
Netlify Edge Functions run on a curated Deno runtime globally distributed across Netlify's CDN. Unlike standard serverless functions that might trigger a cold start or require a trip to a specific region, Edge Functions execute at the point of presence (PoP) closest to the user.
They operate on a request/response lifecycle: they receive the incoming Request, can access metadata via a Context object (including context.geo), and can either return a synthetic response or modify the response coming from the origin using the streaming HTMLRewriter API.
Runtime Constraints
- CPU Limit: 50ms per invocation.
- Memory: 128MB.
- Environment: Deno (ESM modules). Node.js native addons or
fsmodules are not supported.
Worked Example: A/B Testing a Hero Section
Imagine you want to test two different headlines on your homepage. Instead of using a heavy client-side library, we will use an Edge Function to assign a group via a cookie and inject the corresponding text.
1. Create the Edge Function
Create a file at netlify/edge-functions/ab-test.ts. This function checks for an existing ab-group cookie; if none exists, it randomly assigns one.
import { Context } from "@netlify/functions";
export default async (req: Request, context: Context) => {
const cookieHeader = req.headers.get("cookie") || "";
let group = cookieHeader.includes("ab-group=B") ? "B" :
cookieHeader.includes("ab-group=A") ? "A" : null;
if (!group) {
group = Math.random() > 0.5 ? "A" : "B";
}
const response = await context.next();
// Use HTMLRewriter to swap the text in an element with id="hero-title"
const rewrittenResponse = new HTMLRewriter().
on("#hero-title", {
element(el) {
el.setInnerContent(group === "B" ? "Welcome to the Future!" : "Hello and Welcome!");
}
}).
transform(response);
// Persist the group in a cookie so the user sees the same version on refresh
rewrittenResponse.headers.append("Set-Cookie", `ab-group=${group}; Path=/; Max-Age=604800`);
return rewrittenResponse;
};
2. Configure Routing in netlify.toml
Map the function to your homepage in the netlify.toml file located in your project root.
[[edge_functions]]
path = "/"
function = "ab-test"
3. Local Verification
Run the following command in your terminal to test the logic without deploying:
# Run with Netlify CLI
netlify dev
Visit http://localhost:8888 and inspect the cookies in your browser's DevTools. Refresh the page to ensure the headline remains consistent for your assigned group.
Trade-offs and Limitations
While Edge Functions are powerful, they are not a replacement for a full backend. The 50ms CPU limit means you cannot perform heavy computation or complex data processing. Additionally, HTMLRewriter is a single-pass streaming transformer. If your transformation depends on a piece of data found at the bottom of the HTML document to change something at the top, you would need to buffer the response, which risks exceeding the 128MB memory limit.
Verifying Production Results
Once deployed, you can verify the function is executing by checking the Functions > Edge tab in the Netlify Dashboard. Look for the following metrics:
- Invocations: Confirm the count increases as you visit the site.
- Duration: Ensure the average execution time is well below 50ms.
- Response Headers: Use
curl -I https://your-site.netlify.appto verify theSet-Cookieheader is present.
Actionable Closing
Identify a high-traffic page where client-side redirects or content swaps are causing a visible layout shift. Move that logic into an Edge Function using HTMLRewriter. By handling the modification at the edge, you improve Core Web Vitals (specifically Cumulative Layout Shift) and provide a seamless user experience without sacrificing the speed of a static site.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.