Suggestions
← TIL
~3 min read
#edge-native#astro-6#performance#ab-testing#vercel

A/B Testing Without JS: Avoid CLS and Boost Edge Performance

When testing UI variants without sacrificing performance, you want to eliminate client-side JavaScript and avoid CLS so users experience smooth loading on any connection.

Running A/B testing on the client (via scripts like Optimizely or VWO) is shooting yourself in the foot regarding Web Vitals. Sending 53.4kb of JavaScript just to decide if a button should be blue or red means you’ve already lost the LCP battle and, almost certainly, introduced a CLS (Cumulative Layout Shift) that ruins the user experience.

The solution isn’t to optimize the script, but to eliminate it from the client entirely.

The Zero-JS Architecture#

The key is Edge Middleware. By intercepting the request before it reaches the server (or the CDN), we can decide which version of the content to deliver without the browser having to process a single line of testing logic.

User
Edge (Middleware)
Origin (A/B)

Implementation in Astro 6 + Vercel#

Astro 6 features a native Edge runtime that handles internal rewrites before the first byte leaves the CDN. The workflow follows these four steps:

  1. Identify the user: Check for an existing bucket cookie.
  2. Assign bucket: If missing, randomly assign one (50/50) and set the cookie.
  3. Perform the Rewrite: Change the internal request path without changing the visible URL for the user.
  4. Vary Header: Ensure the CDN caches both versions independently using the Vary: Cookie header.
src/middleware.ts
import { defineMiddleware } from "astro:middleware";

export const onRequest = defineMiddleware(async (context, next) => {
  const cookieName = "ab-test-bucket";
  let bucket = context.cookies.get(cookieName)?.value;

  if (!bucket) {
    bucket = Math.random() < 0.5 ? "control" : "variant-a";
    context.cookies.set(cookieName, bucket, { path: "/", httpOnly: true });
  }

  // If it's the variant, perform an efficient internal rewrite
  if (bucket === "variant-a" && context.url.pathname === "/") {
    return next("/v1/experimental-home/");
  }

  return next();
});

Impact Comparison#

Moving this logic to the Edge isn’t just about aesthetics. On mid-range devices with unstable connections (common in rural areas), the performance delta is non-trivial:

Client-side vs Edge-side Testing

Edge-side (Astro 6)

  • 0ms main thread blocking
  • Non-existent CLS (Visual Stability)
  • Works without JS in the browser
  • Security: user never sees the logic

Client-side (Legacy)

  • FOUC (Flash of Unstyled Content)
  • Negative impact on LCP/INP
  • External script dependency
  • Easy to block by AdBlockers

Digital Equity: From Asunción to rural Itapúa#

Accessibility and Equity

By removing heavy scripts, you’re not just winning at Lighthouse. You’re enabling someone with a 5-year-old phone and a 3G connection in Itapúa to navigate your site as smoothly as someone with an iPhone 15 in the capital city. Performance is an invisible accessibility ramp.

Visible URL remains the same, bucket is persistent, and JS is ZERO.

If you want to take this a step further, you can integrate Astro 6 and the Unified Runtime to ensure your middleware and functions share the same execution environment.

Link copied to clipboard