Meta Pixel Event Tracking on Episerver | OpsBlu Docs

Meta Pixel Event Tracking on Episerver

Implement standard and custom Meta Pixel events for Facebook advertising on Episerver CMS and Commerce

Learn how to implement Meta Pixel (Facebook Pixel) event tracking on Episerver (Optimizely) CMS and Commerce for effective Facebook advertising.

Prerequisites

Meta Pixel Event Types

Standard Events

Meta provides predefined standard events optimized for Facebook ads:

  • PageView - Page view (auto-tracked with base pixel)
  • ViewContent - Product/content view
  • Search - Search performed
  • AddToCart - Product added to cart
  • AddToWishlist - Product added to wishlist
  • InitiateCheckout - Checkout started
  • AddPaymentInfo - Payment info added
  • Purchase - Purchase completed
  • Lead - Lead form submitted
  • CompleteRegistration - Registration completed
  • Contact - Contact form submitted

Custom Events

Track custom actions specific to your business needs.

Standard Event Implementation

ViewContent Event

Track when users view products or content.

Product Page Template

@using EPiServer.Commerce.Catalog.ContentTypes
@model ProductPageViewModel

@{
    var product = Model.Product;
    var variant = Model.SelectedVariant ?? Model.DefaultVariant;
    var price = variant?.GetDefaultPrice()?.UnitPrice.Amount ?? 0;
    var currency = _currentMarket.GetCurrentMarket().DefaultCurrency.CurrencyCode;
}

<script>
  fbq('track', 'ViewContent', {
    content_type: 'product',
    content_ids: ['@variant?.Code'],
    content_name: '@product.DisplayName',
    content_category: '@GetCategoryPath(product)',
    value: @price,
    currency: '@currency'
  });
</script>

<!-- Product details markup -->
<div class="product-detail">
    <h1>@product.DisplayName</h1>
    <p class="price">@price.ToString("C")</p>
    <button class="add-to-cart"
            data-code="@variant?.Code"
            data-name="@product.DisplayName"
            data-price="@price"
        Add to Cart
    </button>
</div>

Content Page Template

@model ArticlePageType

<script>
  fbq('track', 'ViewContent', {
    content_type: 'article',
    content_ids: ['@Model.ContentLink.ID'],
    content_name: '@Model.Name',
    content_category: '@Model.Category'
  });
</script>

Search Event

Track search queries.

@model SearchPageType

@{
    var searchTerm = Request.QueryString["q"];
    var resultCount = Model.SearchResults?.TotalMatching ?? 0;
}

@if (!string.IsNullOrEmpty(searchTerm))
{
    <script>
      fbq('track', 'Search', {
        search_string: '@searchTerm',
        content_category: 'product',
        content_ids: [@Html.Raw(string.Join(",", Model.SearchResults?.Select(r => $"'{r.Code}'") ?? new string[0]))],
        value: @resultCount
      });
    </script>
}

AddToCart Event

Track products added to cart.

Client-Side Implementation

// /Scripts/meta-pixel-commerce.js
window.MetaPixelCommerce = window.MetaPixelCommerce || {};

MetaPixelCommerce.trackAddToCart = function(productCode, productName, price, quantity, currency) {
  quantity = quantity || 1;
  currency = currency || 'USD';

  // Call your cart API
  fetch('/api/cart/add', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      code: productCode,
      quantity: quantity
    })
  })
  .then(response => response.json())
  .then(data => {
    if (data.success) {
      // Track add to cart
      fbq('track', 'AddToCart', {
        content_ids: [productCode],
        content_name: productName,
        content_type: 'product',
        value: price * quantity,
        currency: currency
      });

      // Update cart UI
      updateCartCount(data.cartItemCount);
    }
  })
  .catch(error => {
    console.error('Error adding to cart:', error);
  });
};

Template Usage

<button
    '@variant.Code',
    '@product.DisplayName',
    @price,
    1,
    '@currency'
);">
    Add to Cart
</button>

AddToWishlist Event

Track wishlist additions.

MetaPixelCommerce.trackAddToWishlist = function(productCode, productName, price, currency) {
  fbq('track', 'AddToWishlist', {
    content_ids: [productCode],
    content_name: productName,
    content_type: 'product',
    value: price,
    currency: currency
  });

  // Call your wishlist API
  fetch('/api/wishlist/add', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ code: productCode })
  });
};

InitiateCheckout Event

Track checkout initiation.

@model CheckoutPageType

@{
    var cart = _orderRepository.LoadCart<ICart>(
        CustomerContext.Current.CurrentContactId,
        "Default");

    var contentIds = cart.GetAllLineItems().Select(li => li.Code).ToArray();
    var total = cart.GetTotal().Amount;
    var currency = cart.Currency.CurrencyCode;
    var itemCount = cart.GetAllLineItems().Sum(li => li.Quantity);
}

<script>
  fbq('track', 'InitiateCheckout', {
    content_ids: [@Html.Raw(string.Join(",", contentIds.Select(c => $"'{c}'")))],
    content_type: 'product',
    value: @total,
    currency: '@currency',
    num_items: @itemCount
  });
</script>

AddPaymentInfo Event

Track payment information step.

MetaPixelCommerce.trackAddPaymentInfo = function(value, currency, paymentMethod) {
  fbq('track', 'AddPaymentInfo', {
    content_type: 'product',
    value: value,
    currency: currency,
    payment_method: paymentMethod
  });
};

// Call when payment method is selected
document.querySelector('#payment-method').addEventListener('change', function(e) {
  var cartTotal = parseFloat(document.querySelector('[data-cart-total]').dataset.cartTotal);
  var currency = document.querySelector('[data-currency]').dataset.currency;

  MetaPixelCommerce.trackAddPaymentInfo(cartTotal, currency, e.target.value);
});

Purchase Event

Track completed purchases on the order confirmation page.

@model OrderConfirmationPageType

@{
    var orderId = RouteData.Values["orderNumber"]?.ToString();

    if (!string.IsNullOrEmpty(orderId))
    {
        var order = _orderRepository.Load<IPurchaseOrder>(orderId);

        if (order != null)
        {
            var contentIds = order.GetAllLineItems().Select(li => li.Code).ToArray();
            var total = order.GetTotal().Amount;
            var currency = order.Currency.CurrencyCode;
            var itemCount = order.GetAllLineItems().Sum(li => li.Quantity);
        }
    }
}

@if (order != null && HttpContext.Items["PixelPurchaseTracked"] == null)
{
    <script>
      fbq('track', 'Purchase', {
        content_ids: [@Html.Raw(string.Join(",", contentIds.Select(c => $"'{c}'")))],
        content_type: 'product',
        value: @total,
        currency: '@currency',
        num_items: @itemCount
      });
    </script>

    @{
        HttpContext.Items["PixelPurchaseTracked"] = true;
    }
}

Prevent Duplicate Purchase Events

public class PixelPurchaseTrackingFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var orderId = filterContext.RouteData.Values["orderNumber"]?.ToString();

        if (!string.IsNullOrEmpty(orderId))
        {
            var cookieName = $"fb_pixel_tracked_{orderId}";
            var cookie = filterContext.HttpContext.Request.Cookies[cookieName];

            if (cookie != null)
            {
                filterContext.HttpContext.Items["PixelPurchaseTracked"] = true;
            }
            else
            {
                filterContext.HttpContext.Response.Cookies.Add(new HttpCookie(cookieName, "1")
                {
                    Expires = DateTime.Now.AddDays(7)
                });
            }
        }
    }
}

Lead Event

Track lead form submissions.

@model ContactPageType

<form id="contact-form" handleContactSubmit(event)">
    <input type="text" name="name" placeholder="Name" required />
    <input type="email" name="email" placeholder="Email" required />
    <textarea name="message" placeholder="Message" required></textarea>
    <button type="submit">Submit</button>
</form>

<script>
  function handleContactSubmit(event) {
    event.preventDefault();

    // Track Lead event
    fbq('track', 'Lead', {
      content_name: 'Contact Form',
      content_category: 'contact'
    });

    // Submit form
    event.target.submit();
  }
</script>

CompleteRegistration Event

Track user registrations.

@model RegisterPageType

<form id="registration-form" handleRegistration(event)">
    <input type="email" name="email" placeholder="Email" required />
    <input type="password" name="password" placeholder="Password" required />
    <button type="submit">Register</button>
</form>

<script>
  function handleRegistration(event) {
    event.preventDefault();

    var form = event.target;
    var formData = new FormData(form);

    fetch('/api/account/register', {
      method: 'POST',
      body: formData
    })
    .then(response => response.json())
    .then(data => {
      if (data.success) {
        // Track CompleteRegistration
        fbq('track', 'CompleteRegistration', {
          content_name: 'User Registration',
          status: 'completed'
        });

        // Redirect to success page
        window.location.href = data.redirectUrl;
      }
    });

    return false;
  }
</script>

Custom Events

Track custom actions specific to your business.

Custom Event Structure

fbq('trackCustom', 'EventName', {
  parameter1: 'value1',
  parameter2: 'value2'
});

Examples

Newsletter Subscription

function trackNewsletterSignup() {
  fbq('trackCustom', 'NewsletterSignup', {
    source: 'footer',
    category: 'engagement'
  });
}

Download Tracking

function trackDownload(fileName, fileType) {
  fbq('trackCustom', 'FileDownload', {
    file_name: fileName,
    file_type: fileType,
    content_category: 'resources'
  });
}

// Usage
<a href="/documents/whitepaper.pdf" 'PDF')">
  Download Whitepaper
</a>

Video Interactions

function trackVideoEvent(action, videoTitle) {
  fbq('trackCustom', 'VideoInteraction', {
    video_action: action,
    video_title: videoTitle
  });
}

// Track video play
video.addEventListener('play', function() {
  trackVideoEvent('play', 'Product Demo Video');
});

// Track video completion
video.addEventListener('ended', function() {
  trackVideoEvent('complete', 'Product Demo Video');
});

Content Engagement

// Track scroll depth
var scrollDepth = [25, 50, 75, 100];
var reached = [];

window.addEventListener('scroll', function() {
  var scrollPercent = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 100;

  scrollDepth.forEach(function(depth) {
    if (scrollPercent >= depth && reached.indexOf(depth) === -1) {
      reached.push(depth);
      fbq('trackCustom', 'ScrollDepth', {
        percent: depth,
        page_type: 'article'
      });
    }
  });
});

Episerver-Specific Events

Block Interaction Tracking

@model CTABlockType

<div class="cta-block">
    <h3>@Model.Heading</h3>
    <button 'BlockInteraction', {
        block_type: '@Model.GetOriginalType().Name',
        block_id: '@Model.ContentLink.ID',
        block_name: '@Model.Name',
        interaction_type: 'cta_click'
    });">
        @Model.ButtonText
    </button>
</div>

Episerver Forms Tracking

using EPiServer.Forms.Core.Events;

[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class FormPixelEventInitialization : IInitializableModule
{
    public void Initialize(InitializationEngine context)
    {
        FormsEvents.Instance.FormSubmitted += OnFormSubmitted;
    }

    private void OnFormSubmitted(object sender, FormsEventArgs e)
    {
        var script = $@"
            <script>
                fbq('track', 'Lead', {{
                    content_name: '{e.FormsContent.Name}',
                    content_category: 'form_submission'
                }});
            </script>
        ";

        HttpContext.Current.Response.Write(script);
    }

    public void Uninitialize(InitializationEngine context)
    {
        FormsEvents.Instance.FormSubmitted -= OnFormSubmitted;
    }
}

Category Page Views

@model CategoryPageType

<script>
  fbq('trackCustom', 'CategoryView', {
    category_id: '@Model.ContentLink.ID',
    category_name: '@Model.Name',
    product_count: @Model.Products.Count()
  });
</script>

Product Comparison

MetaPixelCommerce.trackProductComparison = function(productCodes) {
  fbq('trackCustom', 'ProductComparison', {
    content_ids: productCodes,
    num_items: productCodes.length
  });
};

// Usage when comparison view loads
MetaPixelCommerce.trackProductComparison(['SKU123', 'SKU456', 'SKU789']);

Advanced Event Parameters

User Data Parameters

Improve event matching with user data:

fbq('track', 'Purchase', {
  value: 100.00,
  currency: 'USD',
  content_ids: ['SKU123']
}, {
  // Advanced matching parameters (hashed on client-side)
  em: 'hashed_email@example.com',
  ph: 'hashed_phone',
  external_id: 'user_12345'
});

Server-Side User Data

@{
    var contact = CustomerContext.Current.CurrentContact;
    var hashedEmail = !string.IsNullOrEmpty(contact?.Email)
        ? MetaPixelHelper.GetSHA256Hash(contact.Email.ToLower())
        : null;
}

<script>
  fbq('track', 'Purchase', {
    value: @order.GetTotal().Amount,
    currency: '@order.Currency.CurrencyCode'
  }, {
    em: '@hashedEmail',
    external_id: '@contact?.PrimaryKeyId'
  });
</script>

Event Tracking via GTM

Implement Meta Pixel events through Google Tag Manager.

Step 1: Create Data Layer Event

// Push to data layer
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  'event': 'addToCart',
  'ecommerce': {
    'currencyCode': 'USD',
    'add': {
      'products': [{
        'id': 'SKU123',
        'name': 'Product Name',
        'price': 99.99,
        'quantity': 1
      }]
    }
  }
});

Step 2: Create GTM Trigger

  1. GTM > Triggers > New
  2. Type: Custom Event
  3. Event name: addToCart
  4. Save

Step 3: Create Meta Pixel Tag

  1. GTM > Tags > New
  2. Type: Custom HTML
  3. Code:
<script>
  fbq('track', 'AddToCart', {
    content_ids: [{{DLV - Product ID}}],
    content_name: {{DLV - Product Name}},
    value: {{DLV - Product Price}},
    currency: {{DLV - Currency}}
  });
</script>
  1. Trigger: addToCart (from step 2)
  2. Save and publish

Testing Events

1. Meta Pixel Helper

  1. Install Meta Pixel Helper
  2. Visit your site
  3. Perform actions (add to cart, purchase, etc.)
  4. Check extension for events fired

2. Events Manager Test Events

  1. Go to Meta Events Manager
  2. Select your Pixel
  3. Click "Test Events"
  4. Enter your website URL
  5. Perform actions and verify events appear

3. Browser Console

// Check if fbq is available
console.log(typeof fbq);

// Manually fire test event
fbq('track', 'AddToCart', {
  content_ids: ['TEST123'],
  value: 99.99,
  currency: 'USD'
});

4. Network Tab

  1. Open DevTools Network tab
  2. Filter for facebook.com
  3. Perform action
  4. Check tr? requests
  5. Verify event parameters in request payload

Event Parameters Reference

Required Parameters

Different events require different parameters:

Event Required Parameters
ViewContent content_type, content_ids
Search search_string
AddToCart content_ids, content_type, value, currency
AddToWishlist content_ids, content_type, value, currency
InitiateCheckout content_ids, content_type, value, currency, num_items
AddPaymentInfo value, currency
Purchase value, currency, content_ids
Lead - (no required parameters)
CompleteRegistration status

Common Optional Parameters

  • content_name - Product or content name
  • content_category - Category
  • content_type - Usually 'product'
  • value - Monetary value
  • currency - ISO currency code
  • num_items - Number of items

Best Practices

  1. Use Standard Events: Prefer standard events over custom events when possible
  2. Include Value: Always include value and currency for commerce events
  3. Content IDs: Use consistent product SKUs/codes
  4. Test Thoroughly: Test all events before launching campaigns
  5. Avoid PII: Don't send personally identifiable information unhashed
  6. Mobile Compatibility: Ensure events work on mobile devices
  7. Event Deduplication: Prevent duplicate event firing
  8. Server-Side Events: Consider Conversions API for critical events

Troubleshooting

Events Not Appearing

Check:

  1. Meta Pixel Helper shows event fired
  2. Network tab shows tr? request
  3. Event parameters are formatted correctly
  4. No JavaScript errors in console

Duplicate Events

Solution: Implement event deduplication logic

var eventsFired = {};

function trackEventOnce(eventName, params) {
  var key = eventName + JSON.stringify(params);
  if (!eventsFired[key]) {
    fbq('track', eventName, params);
    eventsFired[key] = true;
  }
}

Events Not Optimizing Campaigns

Check:

  1. Events are firing correctly
  2. Sufficient volume (50+ events/week recommended)
  3. Correct event parameters included
  4. Events linked to correct ad account

Next Steps

Additional Resources