Overview
The personalization engine ingests a structured user-context object embedded in the prompt and uses it to drive dynamic content selection, tier-appropriate pricing displays, and feature gating. The engine runs entirely client-side after the initial server render, keeping latency near zero for the first paint while still delivering tailored experiences.
User context shape
The context object arrives as a serialized JSON blob injected into a <script id="__NIMBUS_CTX__"> tag during SSR. The schema is intentionally flat to keep hydration predictable:
{
"tier": "pro" | "team" | "enterprise",
"features": ["analytics", "export", "api"],
"region": "us-east",
"locale": "en-US",
"experiments": ["pricing_v2", "onboarding_redesign"],
"sessionAge": 142
}Pipeline stages
- 1
Context hydration
On mount, read the DOM node, parse JSON, and store in a module-scoped reactive store. Fall back to a safe default (tier: "free") if the node is missing or malformed.
- 2
Feature resolution
Map the features array against a static capability matrix. Each feature key gates a UI subtree; missing keys render nothing. Experiment flags toggle variant branches.
- 3
Content selection
Use tier + region + locale to pick the correct copy bundle. Bundles are static imports tree-shaken at build time — no runtime fetch waterfall.
- 4
Pricing surface
Tier determines which price card is highlighted. Experiments may override the displayed currency or interval (monthly vs annual default).
Edge cases
- Stale context: If sessionAge exceeds a configurable TTL (default 30 min), re-hydrate from a lightweight profile endpoint before rendering personalized content.
- Missing experiments: Absent keys mean the control variant. Never throw — the engine must degrade gracefully.
- Cross-region pricing: Region drives currency formatting via Intl.NumberFormat. Locale drives date and number separators independently.
Performance notes
The entire pipeline executes synchronously inside a single requestAnimationFrame callback. Content bundles are code-split per locale and lazy-loaded only when the context signals a non-default locale. First paint is always the default English shell; personalization swaps happen in the next frame, invisible to the user.