Server-Side Experiments Overview
Deliver personalized experiences and run A/B tests from your backend using Intempt's Choose API — no flicker, SEO-safe, framework-agnostic.
Server-Side Experiments
Overview & Mental Model
Server-side Experiences allow you to deliver personalized experiences and run A/B tests directly from your backend, instead of applying variations in the browser.
Unlike client-side experiences — where variations are applied after the page loads — server-side Experiences are resolved before the response is sent to the client. Intempt decides what a user should see; your backend decides how to render it.
Client-Side vs Server-Side
| Client-Side | Server-Side | |
|---|---|---|
| When decided | In the browser after JS executes | Before rendering, on the server |
| Flicker | Can cause flicker/layout shift | None — user gets correct version on first paint |
| SEO | Limited control over crawlers | Fully SEO-safe |
| Works with | Browser only | SSR, APIs, mobile backends |
How It Works
- Configure Experiences or personalizations in Intempt
- Your backend calls the Choose API before rendering
- Intempt returns the decision (variation assignment)
- Your backend applies the result before responding
Intempt does not modify your UI automatically. It only returns a decision. Rendering is always your responsibility.
What Intempt Decides vs What You Control
| Intempt handles | Your backend controls |
|---|---|
| User eligibility | HTML rendering |
| Experience assignment | API response structure |
| Variation consistency | Feature flags |
| Segmentation & targeting logic | Layout selection |
| Personalization rules | UI composition |
This separation keeps Intempt framework-agnostic.
When to Use Server-Side Experiences
- Server-rendered pages (SSR)
- Feature flags controlled from the backend
- Personalized API responses
- SEO-sensitive landing pages
- Mobile app backends
- High-performance personalization
Choose API
The Choose API resolves server-side Experiences and personalizations before rendering.
Endpoint
POST https://api.intempt.com/v1/{orgName}/projects/{projectName}/optimization/choose-api?apiKey=YOUR_API_KEY| Parameter | Description |
|---|---|
orgName | Intempt organization name |
projectName | Project containing the Experience |
apiKey | API key (query parameter) |
Resolve by Experience Name
{
"identification": {
"userId": "user_123456"
},
"names": ["demo-server-side-experience"],
"device": "mobile",
"sessionId": "my_session_XXX"
}Resolve by Group
{
"identification": {
"userId": "user_123456"
},
"groups": ["my-group"]
}Identity Methods
Use userId if the user already exists in Intempt:
{
"identification": {
"userId": "user_123456"
}
}Optional context fields:
| Field | Description |
|---|---|
sessionId | Session identifier for consistency within a session |
device | "mobile" or "desktop" |
Example Response
{
"choices": [
{
"name": "demo-server-side-personalization-most-popular",
"group": "my-group",
"body": {
"label": "My most popular products PERSONALIZATION",
"products": [
{
"price": "250.0",
"title": "PMC Bronze 9mm",
"category": "Ammunition"
}
]
}
}
]
}Applying Experience Results
Response Structure
{
"choices": [
{
"name": "experience-name",
"group": "group-name",
"body": {}
}
]
}Application Patterns
Text / Content replacement
{ "headline": "Try our new premium plan" }Replace server-rendered copy before sending the response.
Feature flags
{
"enableNewCheckout": true,
"layout": "v2"
}Apply logic before rendering — never after.
Structured personalization
{
"products": [{ "title": "Product A", "price": "250.0" }]
}Insert into HTML, API response, or mobile payload.
Handling Multiple Choices
- Iterate over
choices - Match by
name - Never rely on index order
Fallback Handling
If the API fails or returns no choices, always render the default experience. Define defaults for every Experience before deploying.
End-to-End Flow
- User request — SSR, API, or mobile backend receives request
- Identify user — resolve
userIdorsourceId + profileId - Call Choose API — before any rendering occurs
- Intempt resolves — eligibility, targeting, variation allocation
- Backend applies result — layout, data, flags
- Respond to client — HTML, JSON, or mobile payload
- Consistency — same identity always returns the same Experience
- Measure & iterate — track events normally
Use Cases
| Use Case | Why Server-Side |
|---|---|
| SEO-sensitive pages | No flicker, crawler-safe, deterministic HTML |
| Feature flags | Treat as config, always define defaults |
| Personalized content | Structured payloads, predictable schema |
| Multi-tenant / B2B | Use accountId, separate account vs user logic |
| Mobile & API | Platform-agnostic payloads, backend-controlled rollouts |
Common Mistakes
- Calling Choose API after rendering has started
- Expecting Intempt to inject UI automatically
- Encoding business logic inside Experience bodies
- Not defining fallback defaults
When NOT to Use Server-Side Experiences
- Micro-interactions and DOM-only changes
- Ultra-high-frequency UI events
- Cases where client-side rendering is acceptable
Summary
Intempt decides what should happen. Your backend decides how it happens.
- Faster delivery — decision made before the response
- No flicker — correct version on first paint
- SEO-safe — crawler always sees final HTML
- Full backend control — framework-agnostic integration
