Edge-Side Personalization
What 'Edge' Actually Means Here
Edge-side personalization means deciding what content a visitor sees — based on geography, referrer, device, returning-visitor status, or an experiment bucket — in compute that runs at a CDN point-of-presence close to the visitor, rather than in a centralized origin server or in client-side JavaScript after the page loads. Platforms like Cloudflare Workers, Vercel Edge Middleware, and Fastly Compute@Edge let you run this logic with single-digit-millisecond overhead, geographically distributed, instead of a full origin round-trip or a client-side flash-of-unpersonalized-content.
Why Not Just Personalize Client-Side?
Client-side personalization (reading a geolocation API or cookie in the browser, then swapping DOM content) is simple to implement but suffers the same flicker problem covered in the A/B testing lesson, and it's invisible to search crawlers that don't execute personalization scripts the way a real visitor's session would. Edge-side personalization renders the correct, final version of the page in the response itself — no swap, no flicker, and (if done carefully) crawlable content that reflects your default/baseline experience.
import { NextRequest, NextResponse } from "next/server";
export function middleware(request: NextRequest) {
const country = request.geo?.country ?? "US"; // Vercel populates geo at the edge
const url = request.nextUrl.clone();
// Rewrite EU visitors to a localized/compliance-adjusted variant
// without changing the URL the visitor sees.
if (["DE", "FR", "IT", "ES", "NL"].includes(country)) {
url.pathname = `/eu${request.nextUrl.pathname}`;
return NextResponse.rewrite(url);
}
const response = NextResponse.next();
response.headers.set("x-visitor-country", country);
return response;
}
export const config = { matcher: "/landing/:path*" };Rewrite, Don't Redirect, for Personalization
The Caching Conflict, Again
Edge personalization and edge caching want opposite things: caching wants one shared response; personalization wants a response that varies by visitor attribute. The resolution is to cache by the dimension you're personalizing on — a Vary header or a custom cache key incorporating country/segment, so you cache N variants instead of one, rather than disabling caching entirely. For a handful of discrete segments (3-5 countries, 2-3 device categories) this works well; for near-infinite personalization dimensions (every individual visitor), you need to limit full-page caching to the non-personalized shell and personalize only a specific slot via edge-side includes or a client-rendered component.
Common Personalization Dimensions in Practice
- Geography: currency, language, region-specific compliance copy, local case studies.
- Traffic source/UTM: swapping headline copy to match the ad creative a visitor clicked (message match), a well-documented conversion lever.
- Returning vs new visitor: hiding an intro offer already claimed, or showing a 'welcome back' variant.
- Device category: not just responsive layout, but genuinely different content priority (a shorter form on mobile).
- Weather/time-of-day: niche but real for certain verticals (see the weather-triggered campaigns lesson).
Edge Compute Has Real Constraints
What's Next?
Geography is the most common personalization dimension in practice — the next lesson digs into geotargeting specifically, including the accuracy limits of IP-based location data.
I build these systems professionally.
Whether it's a RAG pipeline, analytics migration, or AI workflow — let's talk.