Common issues and solutions for Episerver (now Optimizely) CMS and Commerce implementations, including performance, tracking, and integration problems.
Quick Diagnosis
Performance Issues
| Symptom | Likely Cause | Solution |
|---|---|---|
| Slow page loads | Large scripts blocking render | Optimize LCP |
| Content jumping | Async content loading | Fix CLS |
| High server response time | Database queries, caching | Check caching configuration |
| Large bundle sizes | Unoptimized assets | Enable bundling/minification |
Tracking Issues
| Symptom | Likely Cause | Solution |
|---|---|---|
| No tracking in production | Edit mode check incorrect | Verify PageIsInEditMode logic |
| Events not firing | JavaScript errors | Check browser console |
| Duplicate events | Multiple implementations | Events Not Firing |
| Missing ecommerce data | Data layer incorrect | Check data layer structure |
Edit Mode Issues
| Symptom | Likely Cause | Solution |
|---|---|---|
| Tracking in edit mode | Missing edit mode check | Add PageIsInEditMode check |
| Scripts break editor | Conflicting JavaScript | Wrap in edit mode check |
| Content blocks not editable | JavaScript interference | Disable scripts in edit mode |
Performance Troubleshooting
Core Web Vitals
Episerver-specific guidance for optimizing Core Web Vitals:
Largest Contentful Paint (LCP)
Target: < 2.5 seconds
Common Episerver LCP issues:
- Large hero images from Media Library
- Render-blocking scripts in
<head> - Slow server response times
- Unoptimized content delivery
View LCP Troubleshooting Guide
Cumulative Layout Shift (CLS)
Target: < 0.1
Common Episerver CLS issues:
- Content areas loading asynchronously
- Block rendering causing shifts
- Visitor group personalization
- Dynamic content injection
View CLS Troubleshooting Guide
First Input Delay (FID) / Interaction to Next Paint (INP)
Target: FID < 100ms, INP < 200ms
Common causes:
- Heavy JavaScript from tracking scripts
- Large Episerver Forms
- Edit mode JavaScript loading in view mode
- Unoptimized event handlers
Page Load Performance
Slow Server Response Time
Diagnosis:
// Add timing header to see server processing time
public class PerformanceHeaderFilter : ActionFilterAttribute
{
private Stopwatch _stopwatch;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
_stopwatch = Stopwatch.StartNew();
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
_stopwatch.Stop();
filterContext.HttpContext.Response.Headers.Add(
"X-Server-Timing",
$"app;dur={_stopwatch.ElapsedMilliseconds}"
);
}
}
Common Solutions:
- Enable output caching
- Optimize database queries
- Use content delivery cache
- Implement Redis caching
- Review Find queries
Render-Blocking Resources
Check for blocking scripts:
<!-- BAD: Blocking script in head -->
<head>
<script src="/Scripts/large-library.js"></script>
</head>
<!-- GOOD: Async or deferred -->
<head>
<script src="/Scripts/large-library.js" defer></script>
</head>
Episerver Client Resources:
// Load scripts at footer (non-blocking)
context.Locate.Advanced.GetInstance<IClientResourceService>()
.RequireScript("/Scripts/app.js")
.AtFooter();
Asset Optimization
Bundling and Minification
Enable in CMS 12+:
// Startup.cs
public void Configure(IApplicationBuilder app)
{
app.UseStaticFiles(new StaticFileOptions
{ =>
{
ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=31536000");
}
});
// Enable response compression
app.UseResponseCompression();
}
For CMS 11:
<!-- web.config -->
<system.web>
<compilation debug="false" targetFramework="4.7.2" />
</system.web>
Image Optimization
Use Episerver ImageResizer:
@{
var imageUrl = Url.ContentUrl(Model.Image);
var optimizedUrl = $"{imageUrl}?width=800&quality=80&format=webp";
}
<img src="@optimizedUrl"
alt="@Model.ImageAlt"
width="800"
height="600"
loading="lazy" />
Tracking Troubleshooting
Analytics Not Working
Scripts Not Loading
Check 1: Edit Mode Detection
// Correct way (CMS 12+)
var isEditMode = EPiServer.Editor.PageEditing.PageIsInEditMode;
// Correct way (CMS 11)
var isEditMode = PageEditing.PageIsInEditMode(HttpContext);
Check 2: Content Security Policy
<!-- web.config -->
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Content-Security-Policy"
value="script-src 'self' 'unsafe-inline' https://*.googletagmanager.com https://*.google-analytics.com https://connect.facebook.net;" />
</customHeaders>
</httpProtocol>
</system.webServer>
Check 3: Browser Console
- Open DevTools (F12)
- Check Console tab for errors
- Look for "Refused to load" or "Refused to execute"
Events Not Firing
Common causes:
- JavaScript errors
- Incorrect event syntax
- GTM trigger not configured
- Ad blockers (expected behavior)
Duplicate Events
Cause: Multiple tracking implementations
Solution: Search codebase
# Search for GA4
grep -r "gtag('config'" .
grep -r "googletagmanager.com/gtag" .
# Search for Meta Pixel
grep -r "fbq('init'" .
grep -r "fbevents.js" .
# Search for GTM
grep -r "googletagmanager.com/gtm.js" .
Ecommerce Tracking Issues
Missing Purchase Data
Check 1: Order Confirmation Loading
var orderId = RouteData.Values["orderNumber"]?.ToString();
if (string.IsNullOrEmpty(orderId))
{
// Order ID not found - check routing
}
var order = _orderRepository.Load<IPurchaseOrder>(orderId);
if (order == null)
{
// Order not found - check order loading
}
Check 2: Duplicate Prevention Ensure you're not preventing first-time tracking:
@if (order != null && HttpContext.Items["OrderTracked"] == null)
{
<!-- Track purchase -->
}
Incorrect Product Data
Check data layer structure:
// Browser console
console.log(window.dataLayer);
// Verify ecommerce object
window.dataLayer.forEach((item, index) => {
if (item.ecommerce) {
console.log(`Item ${index}:`, item.ecommerce);
}
});
Edit Mode vs. View Mode
Tracking in Edit Mode
Problem: Analytics fire when editing content
Solution: Add edit mode checks
@{
var isEditMode = EPiServer.Editor.PageEditing.PageIsInEditMode;
}
@if (!isEditMode)
{
<!-- Tracking scripts here -->
}
Preview Mode Considerations
Decision: Should tracking fire in preview mode?
Option 1: Disable in preview
var isPreviewMode = EPiServer.Web.ContextMode.Current == EPiServer.Web.ContextMode.Preview;
if (!isEditMode && !isPreviewMode)
{
// Load tracking
}
Option 2: Enable in preview (to test)
if (!isEditMode)
{
// Load tracking (fires in preview)
}
Scripts Breaking Editor
Problem: JavaScript interferes with edit mode
Solutions:
- Wrap all scripts in edit mode check
- Use edit mode-aware event handlers
- Check
PageEditing.PageIsInEditModebefore DOM manipulation
Multi-Site Issues
Wrong Tracking ID
Problem: Site A uses Site B's tracking ID
Diagnosis:
// Log current site info
var currentSite = SiteDefinition.Current;
_logger.Information($"Site: {currentSite.Name}, Host: {currentSite.SiteUrl.Host}");
Solution: Use site-based configuration
public static string GetGATrackingId(this SiteDefinition site)
{
return site.SiteUrl.Host switch
{
"www.site1.com" => "G-SITE1XXXX",
"www.site2.com" => "G-SITE2XXXX",
_ => null
};
}
Multi-Language Issues
Problem: Language not tracked correctly
Solution: Include language in data layer
@{
var language = (Model as ILocalizable)?.Language?.Name ?? "en";
}
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'language': '@language',
'pageUrl': '@Url.ContentUrl(Model.ContentLink)'
});
</script>
Content Delivery API (Headless)
Tracking IDs Not Available
Problem: Frontend doesn't have tracking IDs
Solution: Return in API responses
public class ContentApiModelConverter : IContentApiModelConverter
{
public ConvertedContentApiModel Convert(IContent content, ConverterContext converterContext)
{
var model = new ConvertedContentApiModel();
model.Properties.Add("tracking", new
{
gaTrackingId = "G-XXXXXXXXXX",
gtmContainerId = "GTM-XXXXXXX",
metaPixelId = "1234567890"
});
return model;
}
}
CORS Issues
Problem: API requests blocked by CORS
Solution: Configure CORS (CMS 12+)
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("AllowFrontend", builder =>
{
builder.WithOrigins("https://frontend.example.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
}
public void Configure(IApplicationBuilder app)
{
app.UseCors("AllowFrontend");
}
Common Error Messages
"Cannot read property 'push' of undefined"
Cause: dataLayer not initialized before GTM
Solution: Initialize dataLayer before GTM script
<script>
window.dataLayer = window.dataLayer || [];
</script>
<!-- GTM script here -->
"gtag is not defined"
Cause: GA4 script not loaded or blocked
Solutions:
- Check script is loading: Network tab → filter for
gtag - Verify not blocked by CSP
- Check ad blockers disabled (for testing)
- Ensure script loads before
gtag()calls
"fbq is not defined"
Cause: Meta Pixel script not loaded
Solutions:
- Check script loading: Network tab → filter for
fbevents - Verify Pixel ID is correct
- Check CSP headers allow Facebook
- Test with ad blockers disabled
Debugging Tools
Browser Developer Tools
Console: Check for JavaScript errors
// Enable verbose logging
localStorage.setItem('debug', 'true');
Network: Monitor requests
- Filter:
google-analytics.com,googletagmanager.com,facebook.com - Check for 200 status codes
- Inspect request payloads
Application: Check cookies and storage
- Cookies:
_ga,_gidfor GA4 - LocalStorage:
dataLayerpersistence
Extensions
- Google Tag Assistant: Verify GTM/GA4 setup
- Meta Pixel Helper: Check Meta Pixel events
- DataLayer Inspector: View GTM data layer
- Lighthouse: Performance auditing
Server-Side Debugging
Enable detailed logging:
// log4net.config or appsettings.json
{
"EPiServer": {
"Logging": {
"Level": "Debug"
}
}
}
Log tracking events:
_logger.Debug($"Tracking event: {eventName}, Parameters: {JsonConvert.SerializeObject(parameters)}");
Best Practices
- Always Check Edit Mode: Prevent tracking in edit mode
- Test Across Modes: Test in view, edit, and preview modes
- Use Configuration: Store IDs in config, not hard-coded
- Implement Error Handling: Gracefully handle tracking failures
- Monitor Performance: Regular performance audits
- Version Control: Track changes to tracking implementations
- Document Custom Events: Maintain event documentation
- Test Before Deploy: Use staging environment for testing