This guide covers setting up Meta Pixel (formerly Facebook Pixel) on Episerver CMS and Commerce (now Optimizely) for Facebook advertising and analytics.
Prerequisites
- Episerver CMS 11+ or CMS 12+
- Meta Business Manager account
- Meta Pixel ID (format: 15-16 digit number)
- Access to Episerver solution and templates
Meta Pixel Overview
Meta Pixel allows you to:
- Track conversions from Facebook ads
- Build custom audiences
- Optimize ad delivery
- Remarket to website visitors
- Track user behavior across devices
Implementation Methods
Method 1: Direct Implementation
Add Meta Pixel directly to your master layout template.
Step 1: Locate Master Layout
Find your main layout file:
Views/Shared/_Layout.cshtmlViews/Shared/_Root.cshtmlViews/Shared/Layouts/_Layout.cshtml
Step 2: Add Base Pixel Code
Add to the <head> section:
@{
var pixelId = "YOUR_PIXEL_ID"; // Replace with your Meta Pixel ID
var isEditMode = EPiServer.Editor.PageEditing.PageIsInEditMode;
}
@if (!isEditMode)
{
<!-- Meta Pixel Code -->
<script>
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '@pixelId');
fbq('track', 'PageView');
</script>
<noscript>
<img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=@pixelId&ev=PageView&noscript=1"/>
</noscript>
<!-- End Meta Pixel Code -->
}
Method 2: Configuration-Based Approach
Store Pixel ID in configuration for easier management.
For CMS 12+ (appsettings.json)
{
"MetaPixel": {
"PixelId": "YOUR_PIXEL_ID",
"Enabled": true,
"EnableInEditMode": false
}
}
For CMS 11 (web.config)
<configuration>
<appSettings>
<add key="MetaPixel:PixelId" value="YOUR_PIXEL_ID" />
<add key="MetaPixel:Enabled" value="true" />
<add key="MetaPixel:EnableInEditMode" value="false" />
</appSettings>
</configuration>
Create Configuration Class
public class MetaPixelSettings
{
public string PixelId { get; set; }
public bool Enabled { get; set; }
public bool EnableInEditMode { get; set; }
}
Register in Startup (CMS 12+)
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MetaPixelSettings>(
Configuration.GetSection("MetaPixel"));
services.AddMvc();
}
}
Update Layout Template
@using Microsoft.Extensions.Options
@inject IOptions<MetaPixelSettings> MetaSettings
@{
var metaSettings = MetaSettings.Value;
var isEditMode = EPiServer.Editor.PageEditing.PageIsInEditMode;
var shouldLoadPixel = metaSettings.Enabled &&
!string.IsNullOrEmpty(metaSettings.PixelId) &&
(!isEditMode || metaSettings.EnableInEditMode);
}
@if (shouldLoadPixel)
{
<!-- Meta Pixel Code -->
<script>
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '@metaSettings.PixelId');
fbq('track', 'PageView');
</script>
<noscript>
<img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=@metaSettings.PixelId&ev=PageView&noscript=1"/>
</noscript>
<!-- End Meta Pixel Code -->
}
Method 3: Multi-Site Configuration
Manage different pixels for multiple sites.
Site Extension Method
public static class SiteDefinitionExtensions
{
public static string GetMetaPixelId(this SiteDefinition site)
{
return site.SiteUrl.Host switch
{
"www.site1.com" => "111111111111111",
"www.site2.com" => "222222222222222",
"www.site3.com" => "333333333333333",
_ => null
};
}
}
Or use site-level properties:
[UIHint("Textarea")]
public virtual string MetaPixelId { get; set; }
Use in Template
@{
var currentSite = SiteDefinition.Current;
var pixelId = currentSite.GetMetaPixelId();
var isEditMode = EPiServer.Editor.PageEditing.PageIsInEditMode;
}
@if (!string.IsNullOrEmpty(pixelId) && !isEditMode)
{
<!-- Meta Pixel Code -->
<script>
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '@pixelId');
fbq('track', 'PageView');
</script>
<noscript>
<img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=@pixelId&ev=PageView&noscript=1"/>
</noscript>
<!-- End Meta Pixel Code -->
}
Method 4: Google Tag Manager Implementation
Use GTM to manage Meta Pixel (recommended for flexibility).
Step 1: Create Meta Pixel Tag in GTM
<script>
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', 'YOUR_PIXEL_ID');
fbq('track', 'PageView');
</script>
<noscript>
<img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=YOUR_PIXEL_ID&ev=PageView&noscript=1"/>
</noscript>
- Set trigger to "All Pages"
- Save and publish
Step 2: Create Variable for Pixel ID
- Go to Variables > New
- Variable Type: "Constant"
- Name: "Meta Pixel ID"
- Value: Your Pixel ID
- Save
Update tag to use variable:
fbq('init', '{{Meta Pixel ID}}');
Method 5: View Component Approach
Create a reusable view component.
Create View Component
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
public class MetaPixelViewComponent : ViewComponent
{
private readonly IOptions<MetaPixelSettings> _settings;
public MetaPixelViewComponent(IOptions<MetaPixelSettings> settings)
{
_settings = settings;
}
public IViewComponentResult Invoke()
{
var settings = _settings.Value;
if (EPiServer.Editor.PageEditing.PageIsInEditMode &&
!settings.EnableInEditMode)
{
return Content(string.Empty);
}
if (!settings.Enabled || string.IsNullOrEmpty(settings.PixelId))
{
return Content(string.Empty);
}
return View("~/Views/Shared/Components/MetaPixel/Default.cshtml",
settings.PixelId);
}
}
Create View
Views/Shared/Components/MetaPixel/Default.cshtml:
@model string
<!-- Meta Pixel Code -->
<script>
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '@Model');
fbq('track', 'PageView');
</script>
<noscript>
<img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=@Model&ev=PageView&noscript=1"/>
</noscript>
<!-- End Meta Pixel Code -->
Use in Layout
<head>
<!-- Other head content -->
@await Component.InvokeAsync("MetaPixel")
</head>
Advanced Pixel Matching
Improve event matching by sending user data.
Server-Side User Data
@{
var user = HttpContext.User;
var contact = CustomerContext.Current.CurrentContact;
var userEmail = contact?.Email;
var userPhone = contact?.Phone;
var userFirstName = contact?.FirstName;
var userLastName = contact?.LastName;
// Hash data for privacy
var hashedEmail = !string.IsNullOrEmpty(userEmail) ? GetSHA256Hash(userEmail.ToLower()) : null;
var hashedPhone = !string.IsNullOrEmpty(userPhone) ? GetSHA256Hash(userPhone) : null;
}
<script>
fbq('init', '@pixelId', {
em: '@hashedEmail',
ph: '@hashedPhone',
external_id: '@contact?.PrimaryKeyId'
});
fbq('track', 'PageView');
</script>
Hashing Helper
using System.Security.Cryptography;
using System.Text;
public static class MetaPixelHelper
{
public static string GetSHA256Hash(string input)
{
if (string.IsNullOrEmpty(input))
return null;
using (var sha256 = SHA256.Create())
{
var bytes = Encoding.UTF8.GetBytes(input);
var hash = sha256.ComputeHash(bytes);
return BitConverter.ToString(hash).Replace("-", "").ToLower();
}
}
}
Content Delivery API (Headless)
For headless Episerver implementations.
Server-Side Setup
Add Pixel ID to API responses:
public class ContentApiModelConverter : IContentApiModelConverter
{
private readonly IOptions<MetaPixelSettings> _metaSettings;
public ContentApiModelConverter(IOptions<MetaPixelSettings> metaSettings)
{
_metaSettings = metaSettings;
}
public ConvertedContentApiModel Convert(IContent content, ConverterContext converterContext)
{
var model = new ConvertedContentApiModel();
model.Properties.Add("metaPixelConfig", new
{
pixelId = _metaSettings.Value.PixelId,
enabled = _metaSettings.Value.Enabled
});
return model;
}
}
Client-Side Implementation (React Example)
// useMetaPixel.js
import { useEffect } from 'react';
export function useMetaPixel(pixelId) {
useEffect(() => {
if (!pixelId) return;
// Load Meta Pixel
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
window.fbq('init', pixelId);
window.fbq('track', 'PageView');
return () => {
// Cleanup if needed
};
}, [pixelId]);
}
// App.js
import { useMetaPixel } from './hooks/useMetaPixel';
function App({ content }) {
useMetaPixel(content.metaPixelConfig?.pixelId);
return (
<div>
{/* Your app */}
</div>
);
}
Environment-Specific Pixels
Use different pixels for development, staging, and production.
appsettings Configuration
appsettings.Development.json:
{
"MetaPixel": {
"PixelId": "DEV_PIXEL_ID",
"Enabled": false
}
}
appsettings.Staging.json:
{
"MetaPixel": {
"PixelId": "STAGING_PIXEL_ID",
"Enabled": true
}
}
appsettings.Production.json:
{
"MetaPixel": {
"PixelId": "PRODUCTION_PIXEL_ID",
"Enabled": true
}
}
Verification
1. Check Pixel Loading
View page source:
- Look for
fbevents.jsscript - Verify Pixel ID is correct
- Confirm NOT present in edit mode
2. Meta Pixel Helper
- Install Meta Pixel Helper
- Visit your site
- Click extension icon
- Verify pixel is found and firing
3. Browser Developer Tools
- Open DevTools Network tab
- Filter for
facebook.com - Look for
tr?requests (pixel events) - Verify
PageViewevent fires
4. Events Manager
- Go to Meta Events Manager
- Select your Pixel
- Click "Test Events"
- Enter your website URL
- Verify PageView event appears
5. Browser Console
// Check if fbq is loaded
console.log(typeof fbq); // Should output "function"
// Check pixel queue
console.log(window._fbq);
Troubleshooting
Pixel Not Loading
Symptoms: No requests to facebook.com
Solutions:
- Verify Pixel ID is correct (15-16 digits)
- Check edit mode detection is working
- Verify no Content Security Policy blocking
- Check browser ad blockers are disabled for testing
Edit Mode Issues
Problem: Pixel loads in Episerver edit mode
Solution: Verify edit mode check:
var isEditMode = EPiServer.Editor.PageEditing.PageIsInEditMode;
Multiple Pixels Firing
Problem: Multiple pixel instances on same page
Solution:
- Search codebase for
fbevents.jsorfbq('init' - Remove duplicate implementations
- Ensure single initialization
Content Security Policy Errors
Error: "Refused to load script from Facebook"
Solution: Update CSP headers in web.config:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Content-Security-Policy"
value="script-src 'self' 'unsafe-inline' https://connect.facebook.net; connect-src 'self' https://www.facebook.com; img-src 'self' https://www.facebook.com;" />
</customHeaders>
</httpProtocol>
</system.webServer>
Ad Blockers
Problem: Pixel blocked by ad blockers
Note: This is expected behavior. Ad blockers will prevent Meta Pixel from loading. Consider:
- Server-side Conversions API (for critical conversions)
- Testing with ad blockers disabled
- Informing users about tracking
Privacy and Compliance
GDPR Compliance
Implement consent management before loading pixel:
// Wait for consent before initializing
function initMetaPixelWithConsent() {
// Check consent (using your consent management platform)
if (hasUserConsent('marketing')) {
fbq('init', 'YOUR_PIXEL_ID');
fbq('track', 'PageView');
}
}
// Call after user provides consent
document.addEventListener('consent-updated', function(e) {
if (e.detail.marketing) {
initMetaPixelWithConsent();
}
});
Data Minimization
Only send necessary data:
- Hash personal information (email, phone)
- Don't send sensitive data
- Use external_id for user matching
- Review data collection practices
Performance Optimization
1. DNS Prefetch
Add to <head>:
<link rel="dns-prefetch" href="//connect.facebook.net">
2. Preconnect
<link rel="preconnect" href="https://connect.facebook.net">
3. Async Loading
Meta Pixel loads asynchronously by default.
Next Steps
- Event Tracking - Implement custom events
- GTM Setup - Use GTM for pixel management
- Troubleshooting - Fix common issues