Meta Pixel Setup on Episerver (Step-by-Step) | OpsBlu Docs

Meta Pixel Setup on Episerver (Step-by-Step)

Complete guide to installing and configuring Meta Pixel (Facebook Pixel) on Episerver CMS and Commerce

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.cshtml
  • Views/Shared/_Root.cshtml
  • Views/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

  1. Go to GTM > Tags > New
  2. Choose "Custom HTML" tag type
  3. Add this 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', '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>
  1. Set trigger to "All Pages"
  2. Save and publish

Step 2: Create Variable for Pixel ID

  1. Go to Variables > New
  2. Variable Type: "Constant"
  3. Name: "Meta Pixel ID"
  4. Value: Your Pixel ID
  5. 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:

  1. Look for fbevents.js script
  2. Verify Pixel ID is correct
  3. Confirm NOT present in edit mode

2. Meta Pixel Helper

  1. Install Meta Pixel Helper
  2. Visit your site
  3. Click extension icon
  4. Verify pixel is found and firing

3. Browser Developer Tools

  1. Open DevTools Network tab
  2. Filter for facebook.com
  3. Look for tr? requests (pixel events)
  4. Verify PageView event fires

4. Events Manager

  1. Go to Meta Events Manager
  2. Select your Pixel
  3. Click "Test Events"
  4. Enter your website URL
  5. 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:

  1. Verify Pixel ID is correct (15-16 digits)
  2. Check edit mode detection is working
  3. Verify no Content Security Policy blocking
  4. 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:

  1. Search codebase for fbevents.js or fbq('init'
  2. Remove duplicate implementations
  3. 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:

  1. Server-side Conversions API (for critical conversions)
  2. Testing with ad blockers disabled
  3. 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

Additional Resources