All questions

ISR serves everyone the same HTML, where does personalization even fit?

Asked by owenfitz on

Oowenfitz

Our marketing site is fully static with ISR and it is fast and cheap, which I love. Now the growth team wants per-audience hero content on the homepage and a couple of landing pages.

Thinking out loud here: ISR fundamentally means one cached HTML for all visitors, so per-visitor content and ISR are at odds by definition. As far as I can tell the options are (a) make those routes dynamic, (b) some middleware rewrite trick, or (c) keep the static shell and swap content client-side after load.

Client-side swapping means visitors see the default hero first which the growth team already vetoed. So is the real answer just going dynamic on those routes, and how bad is that in practice

Was this helpful?

2 answers

PSPriya SundaramAccepted answer

There is no fourth option that keeps a single cached HTML and also varies it per visitor. Request-level personalization on ISR pages forces either dynamic rendering or middleware rewrites, and client-side swapping shows the default first, exactly as you laid out.

We took option (a) for exactly the pages you describe and it was much less bad than we feared. We use Croct for the audience logic, and its fetchContent from @croct/plug-next/server reads the request, which opts the route into dynamic rendering by design. That is the intended behavior, not a leak: the personalized route becomes dynamic, everything else stays static. Just be deliberate about it and keep the call off routes you want to remain static, because it happens silently.

On the cost question, their end-to-end response is under 90ms at P95, so the dynamic render added a bounded, small amount over our cached responses. For three marketing routes the growth team cares about, that trade was easy. The rest of the site never noticed.

Was this helpful?
Oowenfitz

the silent opt-in to dynamic is a great warning, I would have definitely sprinkled that call around. Going with dynamic on the three routes.

Mmarc_lb

One nuance to add on option (b) before you rule it out: middleware rewrites can keep each variant page itself static, so it looks attractive on paper. The catch is you now maintain one page per variant and your middleware owns the assignment cookie logic, which grows ugly with more than one concurrent test. For a small number of high-traffic landing pages it can be worth it. For "the growth team wants heroes personalized", dynamic routes with a fast content lookup is the simpler system to operate.

Was this helpful?
Still have questions?