Server-Side Personalization at Scale
Aspen Dental’s pages needed to speak to the visitor’s nearest office — the right name, phone, and city — without slowing the site down or breaking SEO. I built a personalization pipeline that resolves the visitor’s office on the server, replaces content tokens before the HTML is sent, and renders a fully personalized first paint with no client-side flicker or layout shift.
Context
Aspen Dental is a U.S. healthcare organization with 1,000+ offices nationwide, and its public site is a large, SEO-critical platform of tens of thousands of pages. Marketing wanted landing pages that reflected the visitor’s closest office — surfacing the local name, phone number, city, and nearby landmarks — instead of generic, one-size-fits-all copy.
This built directly on the Gatsby → Next.js SSR migration, which already put server-side rendering and a CloudFront edge in front of every page.
Problem
The obvious way to personalize — read the location in the browser and swap the text after the page loads — is exactly the wrong approach for a site like this:
- Client-side replacement flickers: the generic content paints first, then jumps to the personalized version, causing visible layout shift (poor CLS).
- Search crawlers and social scrapers see the generic, pre-JavaScript markup — so the personalized content is unreliable for SEO.
- Location logic scattered across components is hard to keep consistent and easy to get wrong.
Personalization had to be resolved and rendered before the HTML leaves the server, so the first byte a visitor (or a crawler) receives is already correct.
My Role
- Designed the server-side office-resolution and token-replacement pipeline
- Defined the precedence rules that make personalization deterministic
- Defined the set of personalization tokens available to authors
- Owned the SEO and performance constraints — no flicker, no layout shift
Approach & Key Decisions
Resolving the “home office”
Every request resolves a single home office using a strict order of precedence, so the outcome is always predictable:
- Explicit choice first. A cookie — set when a visitor picks an office — takes highest priority, because it represents deliberate intent.
- Then geolocation. With no cookie, the CDN provides latitude/longitude headers at the edge (via CloudFront), which we use to find the nearest office to those coordinates.
- Then a safe fallback. If neither resolves, personalization falls back to a neutral default rather than failing.
Server-side token replacement
On the initial load the server resolves the office, fetches the matching Contentful experience, replaces the content tokens, and renders the final HTML in one pass. Authors write placeholders directly into their copy — {{officeName}}, {{officePhone}}, {{officeCity}}, {{officeState}}, and {{officeLandmarks}} — and the server fills them in before the page is sent.
Returning visitors and explicit choices
When a visitor changes their office, a Server Action updates the cookie and the UI reruns the replacement logic to refresh the content in place — no full page reload. The cookie is persistent (max-age of one year), so return visits reflect the visitor’s last choice straight from the server.
Why it’s server-side
Because the office is resolved and the tokens are replaced before render, the first paint is already personalized. There is no generic-then-personalized swap, so there’s no flicker and no layout shift — and crawlers receive complete, stable HTML, keeping the personalization SEO-safe.
The composition side of this — how editors build location-specific layouts on top of the resolved office — is covered in Composable Personalization with Contentful Studio.
Results
- Personalized first paint — the nearest office’s details are in the HTML before it’s sent
- No flicker and no layout shift, because nothing is swapped after load
- SEO-safe: crawlers see complete, stable, personalized markup
- Deterministic resolution via cookie → geolocation → fallback precedence
- Return visits honor the visitor’s last chosen office through a persistent cookie
Why This Matters
Personalization usually trades performance and SEO for relevance. Resolving it on the server flips that trade-off: visitors get locally relevant pages, crawlers get stable markup, and Core Web Vitals stay intact — all from one pass on the server.
Continue exploring
Engineering notes
Related case studies