Optimizely Product Recommendations
Implementation Nuances
A comprehensive guide to the four integration methods — JavaScript API, Server-to-Server API, Commerce Connect Native, and Configured Commerce Native — covering feed setup, tracking, rendering, and widget configuration.
Overview & Comparison Matrix
A quick-reference view across all four implementation methods and key capability areas. Use this to determine the right approach for a given customer scenario.
| Capability | JS API (Standalone) | S2S API (Standalone) | Commerce Connect (Native) | Configured Commerce (Native) |
|---|---|---|---|---|
| Relative Difficulty | Medium | Hardest | Medium–Hard | Easiest |
| Feed — Auto-generated? | ✗ Manual/custom | ✗ Manual/custom | ✓ Via CMS export job | ✓ Via CC RSS export job |
| Feed Type (Portal) | Generic / Custom Download | Generic / Custom Download | Generic Upload (push) | Generic Download (pull) |
| Feed Schedule Controlled In | Product Rec Portal | Product Rec Portal | CMS Scheduled Jobs | Product Rec Portal |
| Page Tracking — Auto? | ✗ Manual JS tags | ✗ Manual server POST | ✓ Via [CommerceTracking] attribute | ✓ Via peerius.js (base theme) |
| Click Tracking | Manual (smartRecsClick) | Manual (payload info.smartRecs.click) | Manual (custom component) | ✓ OOB via Product Carousel |
| Rendering Component | Custom JS callback | Custom (JSON response) | Custom Razor views | ✓ OOB Product Carousel widget |
| Authentication | Domain whitelisting + script | clientToken in payload | Site tokens in appsettings.json | Peerius URL + Site Name in Admin |
| Cookie Management | Automatic (browser) | Manual (server-managed) | Automatic (CC package) | Automatic (peerius.js) |
| Session Viewer — Cookie Location | previous_user cookie (easy) | No visible cookie; use URL method | CUID in app (may have encoding) | previous_user cookie (easy) |
| Mobile App Support | ✗ Client-side only | ✓ Required for mobile apps | Partial | ✗ |
| Widget Configuration | Product Rec Portal | Product Rec Portal | Product Rec Portal | Product Rec Portal + Spire CMS |
Standalone · Client-Side JavaScript API
The most common standalone integration. All tracking and rendering happen client-side via the peerius.js script. Relies on browser cookies. Best for websites where server-side control is not required.
Feed Setup
The feed must be created and maintained by the customer or SA team. Optimizely does not auto-generate a feed for standalone integrations.
- Feed formats: RSS 2.0 XML (preferred) or CSV — must be UTF-8 compliant.
- Feed type in portal:
Generic Download(standard) orCustom Download(if SA has modified the feed). - Feed URL: Set in the portal at
Admin › Site Management › Feed Configuration › Configure. - Schedule: Configured directly in the Product Recommendations Portal (schedule tab). The customer must ensure their feed file is updated by the time Optimizely fetches it.
- All products to be recommended must appear in the feed. Removing a product marks it inactive.
- Include all attributes used in widget algorithm rules — attribute names must match exactly.
Tracking Setup (Page & Click)
Script Installation
Include peerius.js on every page, just above the </body> tag:
<script type="text/JavaScript" src="//{sitename}.uat.productrecs.optimizely.com/tracker/peerius.page" charset="UTF-8"> </script> Configure tracking in the Admin Console integration tab:
| Setting | Value |
|---|---|
| Peerius Tracking URL (UAT) | //{sitename}.uat.productrecs.optimizely.com/tracker/peerius.page |
| Peerius Tracking URL (Prod SE) | //{sitename}.peerius.episerver.net/tracker/peerius.page |
| Peerius Tracking URL (Prod US) | //{sitename}.uswe01.productrecs.episerver.net/tracker/peerius.page |
| Peerius Site Name | Your instance name from the Rec Portal (e.g. datademosite2) |
| Peerius API Version | v1_4 |
Page Tracking — PeeriusCallbacks
Declare the PeeriusCallbacks object on every page with apiVersion: "v1_4":
var PeeriusCallbacks = { apiVersion: "v1_4", // page-type tracking payloads go here }; Supported page types: home, product, category, basket, checkout, order, search, wishlist, brand, attribute. Contact Optimizely for custom page types.
Click Tracking
Click tracking must be manually implemented. Use the 64-bit recommendation ID (rec.id) returned in the smartRecs callback:
| Function | When to Use |
|---|---|
Peerius.smartRecsClick(id) | Click navigates to a new page |
Peerius.smartRecsSendClick(id) | User stays on the same page |
Session Viewer — Cookie Location
Open DevTools › Application/Storage › Cookies. Look for the previous_user cookie. The CUID is between the colon (:) and the pipe (|). Format is clean and easy to read for JS implementations.
Rendering Setup
Recommendations are delivered via the PeeriusCallbacks.smartRecs JavaScript callback. You define this function; Optimizely calls it when recommendations are ready.
var PeeriusCallbacks = { apiVersion: "v1_4", smartRecs: function(jsonData) { for (var i = 0; i < jsonData.length; i++) { var widgetData = jsonData[i]; var position = widgetData.position; // Always use position, NOT widget name var recs = widgetData.recs; var container = document.getElementById(position); if (!container || !recs) continue; container.innerHTML = ''; for (var j = 0; j < recs.length; j++) { var rec = recs[j]; var el = document.createElement('div'); el.innerHTML = '<a href="' + rec.url + '?recommendationId=' + rec.id + '" ' + 'onclick="Peerius.smartRecsClick(' + rec.id + ')">' + '<img src="' + rec.img + '" /><span>' + rec.title + '</span>' + '</a>'; container.appendChild(el); } } } }; position, never widget The widget name can change during A/B tests; position is stable and guaranteed unique. Binding your renderer to widget will break A/B test scenarios. Widget Configuration
Widget setup is done entirely in the Product Recommendations Portal — identical process across all standalone implementations:
- Go to Configuration › Product Recommendations › Widgets › Create Widget
- Set Name, Page type, Position (stable ID used in rendering), and Number of Recommendations (1–50)
- Go to Widgets per page and assign widgets to relevant pages
- Add an algorithm stack (up to 11 algorithms; always include a fallback, e.g. popular products)
- For merchandising overrides, create a Campaign under Recommendations › New Campaign
📚 Documentation Sources
JSON Variable Tracking Format · Click Tracking · Recommendations Callback · Migrate JS API 1.3 → 1.4 · Manage WidgetsStandalone · Server-Side Server-to-Server (S2S) API
The most technically demanding implementation. All tracking is performed via server-side POST requests. Cookie management is entirely the client's responsibility. Required for mobile apps. Preferred when server-side control or cookie-bypass is needed.
- Customer has a mobile app requiring recommendations (JS has no client in this context)
- Preference for explicit server-side cookie control (avoids browser cookie blocking)
- Need to avoid third-party client-side script dependencies
- Can be used alongside JS — one application can be JS, another S2S (e.g., website + mobile app)
Feed Setup
Feed setup is identical to the JS API — the customer supplies the feed file independently:
- Feed type in portal:
Generic DownloadorCustom Download - Schedule: Controlled in the Product Recommendations Portal (same as JS API)
- RSS 2.0 XML preferred; must be UTF-8 compliant; include all attributes used in algorithm rules
- Import historical orders before launch to accelerate algorithm learning
Tracking Setup (Page & Click)
Tracking Endpoint
| Environment | URL |
|---|---|
| UAT | https://uat.productrecs.optimizely.com/tracker/smart-api/recommendations |
| Production | https://{sitename}.productrecs.optimizely.com/tracker/smart-api/recommendations |
Method: POST · Format: JSON · Must use HTTPS · Requires clientToken in payload (from portal Admin › Site Management › Development)
Cookie Management — Critical S2S Distinction
peerius.js manages peerius_user and peerius_sess cookies automatically, in S2S you must generate, store, and pass valid CUID (cuid) and session (session) values in every tracking payload. Missing or malformed values will prevent session tracking. | Cookie / Field | Purpose | S2S Responsibility |
|---|---|---|
peerius_user / cuid | Visitor CUID — indefinite lifetime | Client-managed; passed in payload |
peerius_sess / session | Session ID — 4hrs from last activity | Client-managed; passed in payload |
peerius_rid | Tracks clicked recommendations | Client-managed |
Cookie Format (v1.4)
In v1.4, the separator changed from / to |:
// v1.3 (deprecated) "session": "155780550/hKugo5RQsqecUpmlWE6EpFWqmalVrJU" // v1.4 (current) "session": "123456789012|a1b2c3d4e5A6B7C8D9E0f1g2h3i4j5F1G2H3I4J5k1l" "cuid": "09876543210|Z0Y9X8W7V6z5y4x3w2v1U0T9S8R7Q6u5t4s3r2q1P0O"
Page Tracking Payload Example
{ "type": "product", "ip": "10.42.37.139", "session": "123456789012|a1b2c3d4e5...", "cuid": "09876543210|Z0Y9X8W7V6...", "site": "retailer", "clientToken": "1234abcd5678", "channel": "web", "lang": "en-gb", "currentURI": "www.retailer.com/product/RC456.html", "previousURI": "www.retailer.com/product/RC123.html", "userAgent": "Mozilla/5.0 ...", // Mandatory from v1.3+ "product": { "refCode": "RC456" } } Click Tracking
Pass the recommendation ID from the previous response in the next tracking payload:
{ "info": { "smartRecs": { "click": 5637282 // 64-bit rec ID from previous smartRecs response } } } Session Viewer — Finding Your Cookie
- Navigate to a very obscure/low-traffic product URL on the customer's site
- Paste that URL into the Session Viewer search
- If the page was tracked, your session should appear
- Copy the CUID from the session — paste it back into the Session Viewer for future debugging
Rendering Setup
Recommendations are returned in the same JSON response as the tracking request — no separate callback needed. You receive a smartRecs array and are responsible for rendering it server-side or passing it to the front-end template.
| Parameter | Description |
|---|---|
recContent: "full" | Returns full product details (price, image, title, URL) — default |
recContent: "refCodeOnly" | Returns only product ref codes + rec IDs (lighter payload) |
smartProducts: ["smartRecs"] | Use when multiple Optimizely products run on the same page |
showAttributes: "*" | Returns all product attributes in the response |
Widget Configuration
Identical to the JS API — all widget configuration happens in the Product Recommendations Portal. The same widget/campaign/position concepts apply. The position value in the response determines which widget slot to render into.
- Use
position(notwidgetname) to identify render targets - Algorithm stacks, campaigns, and exclusions are configured identically in the portal
- The
clientTokenfor S2S is found atAdmin › Site Management › Developmentin the portal
📚 Documentation Sources
Common Elements (Request Fields) · Recs Only Endpoint · Click Tracking · Migrate S2S 1.3 → 1.4 · Administer the Portal (Session Viewer)Native Integration · NuGet Package Commerce Connect (Native)
Installed via a NuGet package (EPiServer.Personalization.Commerce). Piggybacks on the Commerce Connect CMS infrastructure for feed and tracking. More out-of-box than standalone, but rendering is almost always custom-built due to the bespoke nature of Commerce Connect implementations.
Feed Setup
The feed is generated automatically by a CMS scheduled job — no manual feed file creation required.
How the Feed Works
The Export Product Feed job (available after installing the NuGet package) does two things:
- Serialises the Commerce Connect catalog to XML, compresses it, and stores it as a blob
- Notifies the Product Recommendations REST API that a new catalog is available (passing a callback address + auth token)
Optimizely then calls back to download the blob. This makes it a push/notify mechanism — not a URL-based pull.
Product Export Requirements
A product must meet all of the following to appear in the feed export:
| Requirement | Detail |
|---|---|
| In stock | Must have available inventory |
| Valid prices | Non-expired, valid price entries |
| Published | Must be published in CMS |
| Has variants | Must have at least one variant |
Feed Schedule — Controlled in CMS
| Job | Purpose | Recommended Frequency |
|---|---|---|
| Export Product Feed | Full catalog export (includes deletions, asset/inventory changes) | Every 24 hours |
| Export Product Feed Incrementally | Added/updated products only — does NOT replace the full job | As needed |
Key appsettings.json Configuration
{ "EPiServer": { "Personalization": { "PersonalizationOptions": { "BaseApiUrl": "https://your-env.productrecs.episerver.net", "Site": "your_site_name", "ClientToken": "your_client_token", "AdminToken": "your_admin_token", "Channel": "web", "TrackingMode": "ClientSide", "UsePseudonymousUserId": true, "FeedCatalogName": "YourCatalogName" } } } } ClientToken and AdminToken values (site tokens) are provided by Optimizely during onboarding via email. These must be placed in appsettings.json — unlike standalone implementations which use domain whitelisting or inline payload tokens. Tracking Setup (Page & Click)
Page Tracking via CommerceTracking Attribute
Tracking is applied by decorating controller actions with [CommerceTracking(TrackingType.X)]. The tracking fires in OnActionExecuting, so recommendations are available immediately when the action method is entered:
[CommerceTracking(TrackingType.Product)] public ViewResult ProductPage(ProductPage currentPage) { var recommendations = this.GetRecommendationGroups(); // Each Recommendation has: // .Area → widget name (e.g. "Alternatives", "CrossSell") // .ContentReferences → IEnumerable<ContentReference> of recommended products var model = new ProductPageViewModel(currentPage) { Recommendations = recommendations }; return View(model); } Supported TrackingTypes
Home · Search · Category · Product · Basket · Checkout · Order · Wishlist · Brand · Attribute
Click Tracking Nuance
Click tracking for Commerce Connect is not automatic (unlike Configured Commerce). It must be implemented in the custom rendering component. The 64-bit recommendation ID from the ContentReferences response is used — same approach as the standalone integrations.
Session Viewer — Cookie Location
For Commerce Connect, the CUID will be present in the application (DevTools). However, if the customer is using the server-side variant of the integration, the cookie format may differ — HTML encoding characters appear instead of the actual separator characters:
- Standard format:
cuid: 12345|abcdef...— look between:and| - Server-side encoded format: look between
Dand%(the HTML-encoded colon/pipe) - Client-side variant: standard cookie format, easy to read
Rendering Setup
GetRecommendationGroups()), but the rendering component must be built from scratch to match the site's UI/UX. The out-of-box package does include a basic rendering option, but it is rarely used in practice. Build a custom Razor component:
@foreach (var group in Model.Recommendations) { <div class="rec-widget" data-area="@group.Area"> @foreach (var productRef in group.ContentReferences) { var product = ContentLoader.Get<ProductContent>(productRef); <!-- Render product card here --> } </div> } Widget Configuration
Widget configuration follows the same portal-based approach as standalone integrations:
- Configuration › Product Recommendations › Widgets — create and configure widgets
- Widgets per page — assign to relevant pages
- The
Areaproperty returned byGetRecommendationGroups()corresponds to widget names in the portal - Algorithm stacks and campaigns are configured identically to standalone methods
For multi-site setups, configure Scopes in appsettings.json — each scope maps to a different site/catalog and has its own ClientToken, Site, and BaseApiUrl.
📚 Documentation Sources
Install & Configure Native Package (v15) · Track and Recommend (v15) · Export Catalog (v15) · Scheduled Jobs UI (v15) · Track and Recommend (Latest)Native Integration · Out-of-Box Configured Commerce (Native)
The simplest implementation. Configured Commerce handles feed, tracking, and rendering automatically via built-in integrations and the Spire CMS Product Carousel widget. A customer can often complete this implementation end-to-end following the official documentation with minimal technical overhead.
- Feed is auto-generated via a scheduled export job
- Page tracking & click tracking come out-of-box via
peerius.js - Out-of-box Product Carousel widget handles rendering — just switch the carousel type to "Recommended Products"
- No custom code required for a standard implementation
- SCs can often lead the implementation on-call with the customer
Feed Setup
Step 1 — Enable in Admin Console
- Go to Admin Console › Administration › System › Settings
- Click the Integration tab › Integration Connectors
- Toggle Enable Product Recommendations to Yes
This auto-creates two scheduled jobs: Export Products RSS Feed and Export Historical Orders.
Step 2 — Schedule and Run the Feed Job
- Go to Administration › Jobs › Job Definitions
- Edit the Export Products RSS Feed job
- Set a schedule and fill in the Website Name
- After the job runs, verify the feed at:
Library › Media › UserFiles › _system › ProductRecommendationFeed › Products_RSS_Feed-{WebsiteName}.xml
Step 3 — Import Feed into Product Recommendations Portal
- Go to Admin › Site Management › Feed configuration › Configure
- Set Feed type =
Generic download - Set Feed URL =
{your_site_url}/api/v1/productsrssfeed - Select your Default location (language code)
- Run the feed via the History tab
- Set a daily schedule — run 15–30 minutes after the CC export job
Tracking Setup (Page & Click)
Automatic via peerius.js
peerius.js is automatically included in the base Configured Commerce themes. For custom themes/blueprints, add it manually just above </body>.
Configure the three settings in Admin Console › Integration tab:
| Setting | Value |
|---|---|
| Peerius Tracking URL | Environment-specific URL (UAT / Prod SE / Prod US) — no https:// or www |
| Peerius Site Name | Instance name from Product Recommendations portal (e.g. datademosite2) |
| Peerius API Version | v1_4 |
In the Product Recommendations Portal, add your domain (Admin › Tracking › Domains) and ensure the Script tab is set to Generic format.
Click Tracking
Click tracking comes out-of-box via the Product Carousel widget — no manual implementation required for standard setups. The widget handles the smartRecsClick call automatically.
Session Viewer — Cookie Location
Configured Commerce uses peerius.js under the hood — cookie format is identical to the JS API. Look for the previous_user cookie in DevTools. CUID is between the : and |. Clean, easy to read.
Rendering Setup
Out-of-Box Product Carousel Widget (Spire CMS)
- In Spire CMS, navigate to the target page
- Click Add Widget › select Product Carousel
- Set Carousel Type = Recommended Products
- (Optional) Set Widget Position =
2for a second widget on the same page - Toggle display options (price, rating, etc.) as needed
- Click Save › Publish
| Carousel Type | Placement Restrictions |
|---|---|
| Recommended Products | Any page — primary type for Product Recommendations |
| Top Sellers | Cannot be added to Product Detail page |
| Customers Also Purchased | Cart or Product Detail page only |
Widget Configuration
Widget configuration uses a combination of the Product Recommendations Portal and the Spire CMS widget settings:
- In the portal: create widgets, assign to pages, set algorithm stacks and campaigns (same as all other methods)
- In Spire CMS: the Product Carousel widget's Widget Position field maps to the position configured in the portal
- Multiple widgets on one page: use position 1 and position 2 in the carousel widget settings
- All display toggles (show price, show rating, etc.) are controlled directly in the Spire CMS widget panel — no code required
Universal Concepts & Cross-Implementation Notes
These concepts and nuances apply regardless of implementation method. Understanding them is essential for troubleshooting and strategic consulting across all four integration types.
Feed Management — Configuration Tab
| Feed Type | Used By | Meaning |
|---|---|---|
| Generic Download | JS API, S2S API, Configured Commerce | Optimizely pulls the feed from a URL as-is, no modification |
| Generic Upload | Commerce Connect | Feed is pushed from the CMS export job into Optimizely |
| Custom Download | Any implementation | SA has written a script to transform/modify the feed before ingestion |
| Custom Upload | Any implementation | Upload with SA-written transformation script applied |
Session Viewer — Comparison by Implementation
| Implementation | Cookie Name | Format | Difficulty |
|---|---|---|---|
| JavaScript API | previous_user | CUID between : and | — clean | Easy |
| Configured Commerce | previous_user | Same as JS API — clean | Easy |
| Commerce Connect (client-side) | CUID in app | Standard format with actual colon/pipe | Easy–Medium |
| Commerce Connect (server-side) | CUID in app | HTML-encoded: look between D and % | Medium |
| Server-to-Server | None visible in browser | Use obscure URL method to find session | Hard |
Widget Configuration — Universal
Widget building, campaign creation, and strategy management are identical across all four implementation methods. Once tracking and feed are in place, the portal experience is the same:
- Widgets are created in Configuration › Product Recommendations › Widgets
- Algorithm stacks support up to 11 algorithms — always include a fallback
- Campaigns allow attribute-based rules and exclusions on top of widget strategies
- A/B testing of widget strategies is available in all implementations
- Use
position(notwidgetname) for stable rendering references
Critical Implementation Rules
- refCode consistency is mandatory across product, basket, checkout, and order pages — mismatches break behavior attribution and revenue reporting
- lang field in tracking must match a locale in the latest feed export — mismatch causes empty recommendations
- Domain whitelisting required in the portal for all standalone implementations (Admin › Tracking › Domains)
- 30-day attribution window — clicks on recommendations attribute purchases for up to 30 days
- Historical orders import before launch accelerates algorithm learning for all implementations
- Service URL tab in the portal provides the base tracking script starter for standalone implementations — the site-specific suffix (e.g.
USWE) must be appended to form the complete script URL - Do not re-activate widgets post-deployment — this resets widget configuration to defaults