
Show Personalized Content Blocks in Optimizely CMS
Your marketing team wants to show different promotional banners to first-time visitors versus returning customers. Your product team needs logged-in users to see account-specific content blocks while anonymous visitors get generic messaging. These are exactly the problems Optimizely CMS's Audiences feature (formerly called Visitor Groups) was built to solve.
This guide walks you through configuring personalized content blocks in Optimizely CMS 12, from basic audience setup through advanced ODP integration. Whether you're working with simple web-only criteria or need cross-channel behavioral data driving your personalization, you'll have a working implementation by the end.
Prerequisites
Before starting, confirm you have:
- Optimizely CMS 12 running (PaaS, SaaS, or self-hosted)
- Editor or admin access to the CMS admin interface
- Basic familiarity with the Optimizely editing experience
- Optional: Optimizely Data Platform (ODP) account if you want real-time behavioral segmentation
For custom audience criteria development, you'll also need:
- .NET 6 or 7 development environment
- Visual Studio or VS Code with C# extensions
- Access to your CMS project codebase
Step 1: Create Your Content Blocks
Start by building the content blocks you want to personalize. Each audience segment will see a different block, so you'll typically need at least two or three variants.
Navigate to the Assets panel in Optimizely CMS, then select Blocks. Create a new folder for your personalized content to keep things organized—something like "Homepage Promotions" or "Product CTAs."
Create your first block variant. For this example, we'll make promotional banners:
- Click New Block and select your banner block type
- Fill in the content for returning customers (perhaps featuring loyalty rewards)
- Add images, links, and any other required fields
- Save and publish the block
Repeat this process for each audience variant. You might create:
- A "Welcome Back" banner for returning visitors
- A "New Here?" banner with introductory offers for first-timers
- A generic banner as your fallback for everyone else
Tip: Name your blocks clearly to indicate their audience. "Homepage Banner - Returning Customers" is much easier to manage than "Banner v2 final."
Step 2: Define Your Audiences
Audiences are the rules that determine which visitors see which content. Think of them as filters: if a visitor matches the criteria, they're "in" that audience.
Go to CMS Admin → Audiences (in older interfaces, this might still be labeled "Visitor Groups").
Click Create New Audience and give it a descriptive name like "Returning Visitors" or "Mobile Users from UK."
Now add your criteria. Optimizely includes several built-in options:
Visit-based criteria
- Number of visits (first visit, 2 visits, 10 visits)
- Time since last visit
- Pages viewed in session
Technical criteria
- Device type (mobile, tablet, desktop)
- Browser or operating system
- Screen resolution
Location and source
- Geographic location (country, region, city)
- Referral source
- Landing page URL
- Query string parameters
For a "Returning Visitors" audience, you'd add the Number of Visits criterion and set it to "greater than 1."
You can combine multiple criteria. An audience for "Mobile Users from Germany" would include both a device type criterion (mobile) AND a geographic criterion (Germany). All criteria must match for a visitor to be included.
Save your audience when the criteria are configured.
Step 3: Apply Personalization to Your Blocks
With blocks created and audiences defined, you're ready to connect them. This happens on the page where you want the personalized content to appear.
Edit the page containing your content area. Drag your first block (let's say the returning customer banner) into the content area where you want personalized content.
Right-click on the block (or use the block's context menu) and select Personalization. This creates a "personalized group"—a container that holds multiple block variants, each assigned to different audiences.
The personalization panel opens. You'll see your block with an option to assign audiences. Click to add the "Returning Visitors" audience you created earlier.
Now add your other variants:
- Drag the "First-Time Visitor" banner into the same personalized group
- Assign it to your "First-Time Visitors" audience
- Drag your fallback banner in and leave it assigned to Everyone
The Everyone assignment is critical. This is your fallback content—what visitors see if they don't match any specific audience. Without it, non-matching visitors see nothing at all.
Ordering matters: Audiences are evaluated top to bottom. If a visitor matches multiple audiences, they see the first matching variant. Arrange your variants with the most specific audiences at the top.
Step 4: Add Fallback Content
We touched on this above, but fallback content deserves its own attention because it affects both user experience and SEO.
Every personalized group should include an Everyone variant. This serves multiple purposes:
User experience: Visitors who don't match any criteria still see relevant content rather than an empty space.
SEO indexing: Search engine crawlers typically don't match audience criteria (they're not "returning visitors" or "logged in users"). Without fallback content, crawlers index pages with missing sections, potentially hurting your rankings.
Debugging: When testing, you can verify the fallback displays correctly before checking audience-specific variants.
Our experience shows that teams often forget fallback content during initial setup, then wonder why certain visitors see broken layouts. Make fallback content part of your standard checklist.
To set fallback content, ensure one block in your personalized group has no specific audience assigned, or explicitly assign it to Everyone.
Step 5: Preview Your Personalized Content
Before publishing, verify each audience sees the correct content. Optimizely's preview feature lets you simulate different audience memberships.
In the editor, look for the Preview option, then find Preview as Audience (or "View as Visitor Group" in older interfaces).
Select an audience from the dropdown—say, "Returning Visitors." The preview updates to show exactly what a matching visitor would see.
Test each audience systematically:
- Preview as Returning Visitors → verify returning customer banner displays
- Preview as First-Time Visitors → verify welcome banner displays
- Preview with no audience selected → verify fallback banner displays
For more realistic testing, open the page in an incognito window and manually trigger audience criteria. If you have a "Visits > 1" criterion, visit the page twice to see the returning visitor variant.
Common preview gotchas
- Geographic criteria won't work in preview unless you're actually in that location (or using a VPN)
- Time-based criteria evaluate against the current time, which might not match your test scenario
- Cookie-based criteria persist across preview sessions
Step 6: Configure Advanced Audiences with ODP Integration
For basic personalization, the built-in criteria work well. But what if you want to target visitors based on:
- Products they've browsed across multiple sessions
- Their customer lifetime value from your CRM
- Email engagement patterns
- Cross-device behavior
This is where Optimizely Data Platform (ODP) integration becomes valuable. ODP acts as a customer data platform, unifying behavioral data from multiple sources and exposing it as real-time audiences your CMS can use.
Setting Up ODP Integration
First, ensure your ODP instance is configured and receiving data. This typically involves adding the ODP JavaScript snippet to your site and configuring any server-side data feeds.
In your CMS project, install the ODP integration package:
dotnet add package Optimizely.ODP.VisitorGroups
Configure the connection in your startup:
services.AddOdpVisitorGroups(options =>
{
options.ApiKey = Configuration["ODP:ApiKey"];
options.Endpoint = Configuration["ODP:Endpoint"];
});Creating ODP-Linked Audiences
With the integration active, you'll see new criteria options when creating audiences.
Go to CMS Admin → Audiences → Create New Audience.
In the criteria selection, look for Data Platform → Is In Segment.
This opens a dropdown of all real-time audiences defined in ODP. Select the segment you want—perhaps "High-Value Customers" or "Abandoned Cart in Last 7 Days."
Save the audience and use it exactly like any other audience when personalizing blocks.
What ODP Enables
Real-time ODP audiences update within about 90 seconds of behavioral changes. This means you can target visitors based on actions they took moments ago on other channels.
Working with teams has taught us that ODP integration is most valuable when you have:
- Multi-channel customer journeys where web is just one touchpoint
- Rich behavioral data in your CRM, email platform, or commerce system
- Sophisticated segmentation needs beyond simple visit counts or geography
For simpler use cases, built-in CMS criteria are often sufficient and avoid the complexity of maintaining ODP integration.
Step 7: Create Custom Audience Criteria
Sometimes built-in criteria don't cover your specific needs. Optimizely lets developers create custom criteria that editors can use like any other audience rule.
Here's a practical example: a criterion that checks whether the current visitor is authenticated.
using EPiServer.Personalization.VisitorGroups;
using Microsoft.AspNetCore.Http;
using System.Security.Principal;
[VisitorGroupCriterion(
Category = "User Context",
DisplayName = "Is Authenticated",
Description = "Matches visitors who are logged in")]
public class IsAuthenticatedCriterion : CriterionBase<IsAuthenticatedCriterionSettings>
{
private readonly IHttpContextAccessor _httpContextAccessor;
public IsAuthenticatedCriterion(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public override bool IsMatch(IPrincipal principal, HttpContext httpContext)
{
var user = _httpContextAccessor.HttpContext?.User;
if (Model.RequireAuthentication)
{
return user?.Identity?.IsAuthenticated ?? false;
}
return !(user?.Identity?.IsAuthenticated ?? false);
}
}
public class IsAuthenticatedCriterionSettings : CriterionModelBase
{
[CriterionPropertyEditor(
LabelTranslationKey = "/visitorgroups/criteria/isauthenticated/requireauth",
DefaultValue = true)]
public bool RequireAuthentication { get; set; } = true;
}Register the criterion in your service configuration:
services.AddVisitorGroupCriterion<IsAuthenticatedCriterion>();
After deployment, editors will see "Is Authenticated" under "User Context" when creating audiences.
Custom criteria ideas we've implemented
- Checking membership in specific user roles
- Evaluating custom cookies set by third-party tools
- Matching against query parameters from campaign tracking
- Time-of-day criteria for showing different content during business hours
Common Mistakes to Avoid
Missing fallback content: Already mentioned, but worth repeating. Every personalized group needs an Everyone variant.
Overlapping audiences: If a visitor matches multiple audiences, they see only the first matching variant. Design your audiences to be mutually exclusive when possible, or order them intentionally.
Over-personalization: More segments isn't always better. Each personalized variant needs content creation, testing, and maintenance. Start with two or three high-impact segments before expanding.
Ignoring performance: Audience evaluation happens on every request. Complex criteria or too many personalized regions can slow page loads. Monitor performance after enabling personalization.
Forgetting about caching: Personalized content and full-page caching don't mix well. You'll need output cache variation by audience, fragment caching for personalized regions, or disabling caching for personalized pages entirely.
Testing only in preview: Preview mode is helpful but imperfect. Real-world testing with actual cookies, locations, and sessions catches issues preview misses.
Testing and Verification
A solid testing process catches personalization bugs before they reach production.
Manual testing checklist
- View page in incognito mode → confirm fallback content appears
- Trigger each audience criterion manually (visit multiple times, change device, etc.)
- Verify correct variant displays for each audience
- Check page renders correctly with personalized content hidden (if you disable personalization)
- Test on actual mobile devices, not just browser dev tools
Automated testing considerations
For critical personalization, consider writing integration tests that verify audience matching logic. You can mock the IHttpContextAccessor to simulate different visitor states.
[Fact]
public void AuthenticatedCriterion_MatchesLoggedInUser()
{
var httpContext = new DefaultHttpContext();
httpContext.User = new ClaimsPrincipal(
new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "testuser") }, "test"));
var accessor = Mock.Of<IHttpContextAccessor>(a => a.HttpContext == httpContext);
var criterion = new IsAuthenticatedCriterion(accessor);
criterion.Model = new IsAuthenticatedCriterionSettings { RequireAuthentication = true };
var result = criterion.IsMatch(httpContext.User, httpContext);
Assert.True(result);
}Disabling personalization for debugging
If you suspect personalization is causing issues, you can temporarily disable it site-wide by implementing IPersonalizationEvaluator:
public class DisablePersonalizationEvaluator : IPersonalizationEvaluator
{
public bool IsEnabled(HttpContext context)
{
// Return false to disable all personalization
// Useful for debugging or for specific scenarios like bot traffic
return false;
}
}When disabled, all visitors see only fallback content, and no audience evaluation or cookie storage occurs.
Wrapping Up
Personalized content blocks in Optimizely CMS follow a clear pattern: create your content variants, define the audiences who should see each variant, connect them through the personalization interface, and test thoroughly before launch.
For most projects, the built-in audience criteria handle common scenarios like returning visitors, geographic targeting, or device-based variations. When you need behavioral data from other channels—email engagement, purchase history, or cross-device activity—ODP integration brings that data into your CMS audiences.
We recommend starting simple. Get one personalized block working with two audiences before scaling up. Once you understand the workflow and testing requirements, expanding to more complex scenarios becomes straightforward.
Configuring personalization in Optimizely CMS involves decisions about audience architecture, caching strategy, and content governance that affect long-term maintainability. If you're planning a significant personalization initiative and want to talk through the technical approach, we're available to help you design a setup that scales with your content needs.
