What this recipe solves
Section titled “What this recipe solves”A visitor browses your website — viewing product pages, reading articles, comparing features. They leave without purchasing. When they return the next day, your site shows the same generic content to everyone. Their browsing history, interests, and intent are lost.
This recipe connects three Optimizely products to solve this: ODP captures and unifies visitor behavior, Recommendations uses that data to compute relevant suggestions, and CMS renders those recommendations on the right pages at the right time.
Architecture
Section titled “Architecture”┌──────────────┐ Events ┌──────────────┐│ Website │ ──────────────→ │ ODP ││ (CMS pages) │ │ (profiles) │└──────┬───────┘ └──────┬───────┘ │ │ │ Page request │ Behavioral data │ ▼ │ ┌──────────────┐ │ │ Recs API │ │ │ (models) │ │ └──────┬───────┘ │ │ │ ◄─────── Recommendations ─────┘ │ ▼┌──────────────┐│ CMS Block ││ (renders ││ recs widget)│└──────────────┘Data flow:
- Visitor browses CMS pages → ODP tracks page views, product views, and interactions
- ODP builds a unified customer profile with behavioral history
- When a CMS page loads, the recommendations widget queries the Recs API
- The Recs API uses the visitor’s ODP profile to compute personalized recommendations
- The CMS block renders the recommended products/content
Step 1: Ensure ODP event tracking is active
Section titled “Step 1: Ensure ODP event tracking is active”Product recommendations require behavioral data. Verify that your site is tracking the right events.
Required events:
| Event | When to fire | What it captures |
|---|---|---|
pageview | Every page load | URL, title, content type |
product | Product page view | Product ID, name, category, price |
add_to_cart | Cart addition | Product ID, quantity |
purchase | Completed order | Order ID, products, total |
// Fire on product page load
zaius.event('product', {
product_id: 'SKU-12345',
name: 'Wireless Headphones',
category: 'Electronics > Audio',
price: 79.99,
url: window.location.href,
}); If you have not set up event tracking yet, follow the Set Up Event Tracking guide first.
Step 2: Configure a recommendation model
Section titled “Step 2: Configure a recommendation model”Recommendation models define the algorithm that selects products for each visitor.
Common model types:
| Model | Algorithm | Best for |
|---|---|---|
| Recently viewed | Shows items the visitor viewed | Product detail pages |
| Frequently bought together | Co-purchase analysis | Cart page, product page |
| Similar items | Content/attribute similarity | Category pages |
| Trending | Popular items by recent activity | Homepage, landing pages |
| Personalized | ML model using full behavioral profile | Any page |
Configure your model in the Optimizely Recommendations dashboard:
- Navigate to Recommendations → Models
- Click “Create Model”
- Select the algorithm type
- Set the data source (which ODP events feed the model)
- Configure filters (category, price range, availability)
- Activate the model
Step 3: Create a CMS block for recommendations
Section titled “Step 3: Create a CMS block for recommendations”Build a CMS block type that renders the recommendation widget.
using EPiServer.Core;
using EPiServer.DataAnnotations;
using System.ComponentModel.DataAnnotations;
[ContentType(
DisplayName = "Product Recommendations",
GUID = "f1e2d3c4-b5a6-7890-cdef-012345678901",
Description = "Displays personalized product recommendations")]
public class RecommendationsBlock : BlockData
{
[Display(Name = "Headline", Order = 10)]
public virtual string Headline { get; set; }
[Display(Name = "Model ID", Order = 20)]
[Required]
public virtual string ModelId { get; set; }
[Display(Name = "Max Items", Order = 30)]
public virtual int MaxItems { get; set; } = 4;
[Display(Name = "Fallback Content", Order = 40)]
public virtual ContentArea FallbackContent { get; set; }
} The FallbackContent property is important — if the Recommendations API returns no results (new visitor with no history), the block shows fallback content instead of an empty space.
Step 4: Render recommendations client-side
Section titled “Step 4: Render recommendations client-side”The recommendations widget loads asynchronously to avoid blocking page render.
async function loadRecommendations(modelId, maxItems, containerId) {
const visitorId = zaius.getVisitorId();
const response = await fetch(
`https://api.zaius.com/v3/recommendations/${modelId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': RECS_API_KEY,
},
body: JSON.stringify({
visitor_id: visitorId,
max_results: maxItems,
}),
}
);
const { recommendations } = await response.json();
const container = document.getElementById(containerId);
if (recommendations.length === 0) {
// Show fallback content
container.querySelector('.recs-fallback')?.classList.remove('hidden');
return;
}
// Render product cards
container.innerHTML = recommendations
.map(product => `
<a href="${product.url}" class="recs-card">
<img src="${product.image_url}" alt="${product.name}" />
<h4>${product.name}</h4>
<span class="price">$${product.price}</span>
</a>
`).join('');
} Step 5: Place the block on CMS pages
Section titled “Step 5: Place the block on CMS pages”- Open a CMS page in the editor
- Find a
ContentArea(e.g., “Below Content” or “Sidebar”) - Add a Product Recommendations block
- Set the Headline (e.g., “Recommended for You”)
- Enter the Model ID from Step 2
- Set Max Items (4–8 is typical)
- Optionally add Fallback Content (a promotional block or featured products)
- Publish the page
Step 6: Personalize recommendations with visitor groups
Section titled “Step 6: Personalize recommendations with visitor groups”Combine recommendations with CMS visitor groups for layered personalization:
- New visitors → Show “Trending” recommendations (no personal history yet)
- Returning visitors → Show “Personalized” recommendations (use their browsing history)
- High-value customers → Show premium products with exclusive offers
Set this up by creating a ContentArea with personalized blocks — each visitor group gets a different RecommendationsBlock pointing to a different model.
Measuring effectiveness
Section titled “Measuring effectiveness”Track recommendation performance to validate the approach:
| Metric | What to measure | How |
|---|---|---|
| Click-through rate | % of visitors who click a recommendation | Track recs_click event in ODP |
| Conversion rate | % of recs clicks that lead to purchase | ODP attribution |
| Revenue per impression | Average revenue generated per recs widget view | ODP computed metric |
| Coverage | % of visitors receiving personalized (not fallback) recs | Recs API analytics |
Consider A/B testing the recommendations widget itself — use Web Experimentation to test whether recommendations increase conversion vs. the page without them.