Geo-Personalizing Content at the Edge Without JavaScript

Personalizing user experience based on location is a core requirement for modern web applications. E-commerce sites display localized pricing and currency, marketing pages feature localized phone numbers and copy, and SaaS platforms dynamically adjust language settings. Historically, developers have built these features using one of two approaches: client-side JavaScript personalization or server-side rendering (SSR).

Both approaches suffer from significant drawbacks. Client-side personalization waits for the page to load, fetches the user's location via an API, and updates the DOM, resulting in layout shifts (CLS) and a noticeable flicker.

On the other hand, server-side rendering (SSR) avoids layout shifts but introduces significant latency as the origin application server locates the user and builds the HTML document from scratch.

An elegant solution to this problem is edge personalization. By leveraging global CDN edges running Cloudflare Workers and the native HTMLRewriter API, we can personalize HTML documents on the fly as they stream from the edge to the user. This strategy delivers localized static files with zero client-side JavaScript overhead, maintaining high Core Web Vitals and SEO rankings.

Understanding Edge Geolocation Headers

When an HTTP request hits a Cloudflare Edge node, the runtime automatically enriches the request with geolocation metadata. This information is exposed through custom headers or directly on the request's connection properties. Key geolocation parameters include:

  • cf-ipcountry: The two-letter ISO-3166-1 country code of the client.
  • cf-region-code: The state or region code (e.g., "CA" for California).
  • cf-timezone: The client's local timezone database identifier (e.g., "America/New_York").
  • cf-postal-code: The postal or zip code of the requesting client.
  • cf-metro-code: The metropolitan area code, highly useful for local targeting.

These parameters are resolved using global IP geolocation databases directly on the edge routing layer, eliminating API lookup latency.

Streaming Rewrites with HTMLRewriter

Cloudflare Workers include a built-in API called HTMLRewriter. This utility operates inside the V8 isolate, parsing and modifying HTML streams on the fly using a fast, selector-based parsing engine written in Rust.

Because HTMLRewriter operates on streams, it does not load the entire HTML document into memory. Instead, it reads chunks of HTML, applies modifications, and sends the modified chunks directly to the client. This results in minimal memory usage and very low Time to First Byte (TTFB).

// Example of using HTMLRewriter inside a Cloudflare Worker
export default {
  async fetch(request, env, ctx) {
    const response = await fetch(request);
    
    // Extract geolocation metadata from request headers
    const country = request.cf?.country || 'US';
    const city = request.cf?.city || 'Worldwide';

    return new HTMLRewriter()
      .on('[data-geo-country]', new CountryHandler(country))
      .on('[data-geo-city]', new CityHandler(city))
      .transform(response);
  }
};

class CountryHandler {
  constructor(country) {
    this.country = country;
  }
  element(element) {
    // Modify element attribute or content based on country
    if (this.country === 'GB') {
      element.setInnerContent('Welcome to our UK Store');
    } else {
      element.setInnerContent('Welcome to our Global Store');
    }
  }
}

class CityHandler {
  constructor(city) {
    this.city = city;
  }
  element(element) {
    element.setInnerContent(`Offers available in ${this.city}`);
  }
}

In this worker script, we fetch the original HTML file from a static file source or origin server. Then, we initialize HTMLRewriter, selecting elements with specific data attributes (e.g., [data-geo-country]) and modifying their contents based on the incoming location headers. The entire transformation happens in transit, requiring no client-side scripting.

Caching Topologies for Geo-Localized HTML

One challenge of edge personalization is caching. If a user from Germany visits your website and causes the edge to cache a German-personalized HTML document globally, a subsequent visitor from Japan might receive the German version.

To prevent this, you can customize the cache key to partition cache storage based on geolocation headers. In a Cloudflare Worker, this is achieved by adjusting the cache key URL:

const url = new URL(request.url);
const country = request.cf?.country || 'US';

// Append country code to the cache key URL to partition cache
const cacheKey = new Request(`${url.origin}${url.pathname}?geo=${country}`, request);
const cache = caches.default;

let response = await cache.match(cacheKey);
if (!response) {
  // Fetch from origin and store in cache
  const originalResponse = await fetch(request);
  response = new HTMLRewriter()
    .on('[data-geo-country]', new CountryHandler(country))
    .transform(originalResponse);
  
  // Clone response before writing to cache
  ctx.waitUntil(cache.put(cacheKey, response.clone()));
}
return response;

By appending the country code to the cache URL, you ensure that visitors from different regions hit separate cache allocations, maintaining high cache hit rates without serving incorrect regional variants.

Core Web Vitals and User Privacy Compliance

By shifting personalization to the edge, applications see dramatic improvements in Web Vitals. Largest Contentful Paint (LCP) drops because localized heroes are printed directly in the initial HTML payload. Total Blocking Time (TBT) remains low since the browser is not running heavy geolocation scripts or dynamic hydration.

More importantly, this architecture preserves user privacy. Since the personalization is performed within secure edge isolates, developers can avoid storing precise IP logs in centralized databases, enabling better compliance with GDPR and CCPA regulations.

Streamlining Regional Delivery with Bramsley

Eliminating the performance penalty of client-side localization requires deep coordination between CDN nodes and edge runtime environments. Bramsley Digital Studio builds custom edge personalization topologies designed to serve dynamic content instantly:

  • Sub-Millisecond Parsing: We leverage low-level V8 streams inside HTMLRewriter to mutate DOM structures in transit.
  • Geo-Partitioned Caching: Our systems configure advanced edge cache-key overrides, keeping regional caches isolated and fast.
  • Privacy-First Architecture: Geolocation resolution is handled entirely in-memory at the edge node, avoiding centralized logging of sensitive IP data.

Bramsley Digital Studio

Enterprise Digital Architecture

We engineer digital infrastructure that drives measurable B2B growth. Experts in Legacy System Migration and High-Performance Frontends.

Architecture Specs & Case Studies

Scale Your Operations

  • Legacy System Migration
  • Scalable Infrastructure
  • High-Performance Frontends
  • Global Edge Deployment