Implement Meta Pixel (Facebook Pixel) on your Umbraco site to track conversions, optimize ads, and build targeted audiences. This guide covers Razor view integration, NuGet packages, and IIS-level configuration for .NET environments.
Prerequisites
Before implementing Meta Pixel:
- Meta Business Manager Account - Create at business.facebook.com
- Meta Pixel Created - Set up Pixel in Events Manager
- Pixel ID - Obtain your Pixel ID (format: 16-digit number)
- Umbraco Backoffice Access - Administrator access required
- .NET Development Environment - Visual Studio 2022+ or VS Code
Method 1: Razor View Integration (Recommended)
Step 1: Create Meta Pixel Partial View
Location: /Views/Partials/Analytics/MetaPixel.cshtml
@using Umbraco.Cms.Core.Models.PublishedContent
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
@{
var pixelId = "YOUR_PIXEL_ID"; // Replace with your 16-digit Pixel ID
// Get Pixel ID from Umbraco settings if stored in config
if (Model?.Value<string>("metaPixelId") != null)
{
pixelId = Model.Value<string>("metaPixelId");
}
}
@if (!string.IsNullOrEmpty(pixelId))
{
<!-- 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 -->
}
Step 2: Include in Master Layout
Location: /Views/Master.cshtml
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
@{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@Model?.Value("title") ?? Model?.Name</title>
@* Include Meta Pixel in head *@
@await Html.PartialAsync("~/Views/Partials/Analytics/MetaPixel.cshtml")
@RenderSection("head", required: false)
</head>
<body>
@RenderBody()
</body>
</html>
Step 3: Configure Pixel ID in Umbraco
Option A: Store in appsettings.json
{
"Analytics": {
"MetaPixel": {
"PixelId": "YOUR_PIXEL_ID",
"Enabled": true
}
}
}
Access in Razor:
@inject IConfiguration Configuration
@{
var pixelId = Configuration["Analytics:MetaPixel:PixelId"];
var enabled = Configuration.GetValue<bool>("Analytics:MetaPixel:Enabled");
}
@if (enabled && !string.IsNullOrEmpty(pixelId))
{
@* Include Meta Pixel *@
}
Option B: Create Document Type Property
- Navigate to Settings → Document Types
- Select Site Settings document type
- Add property:
- Name: Meta Pixel ID
- Alias: metaPixelId
- Editor: Textstring
- Save document type
- Navigate to Content → Site Settings
- Enter Pixel ID
- Save and publish
Step 4: Verify Installation
- Build and run Umbraco site
- Install Meta Pixel Helper Chrome extension
- Visit your site
- Click extension icon
- Verify Pixel fires and shows PageView event
Method 2: NuGet Package Integration
Install Community Package
Install-Package Our.Umbraco.MetaPixel
Or via .NET CLI:
dotnet add package Our.Umbraco.MetaPixel
Configure Package
In Program.cs (Umbraco 10+):
using Our.Umbraco.MetaPixel.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.CreateUmbracoBuilder()
.AddBackOffice()
.AddWebsite()
.AddDeliveryApi()
.AddComposers()
.AddMetaPixel(options =>
{
options.PixelId = builder.Configuration["Analytics:MetaPixel:PixelId"];
options.AutoTrackPageView = true;
options.EnableAdvancedMatching = true;
})
.Build();
var app = builder.Build();
// ... rest of configuration
Enable Advanced Matching
Advanced matching improves conversion attribution:
@using Umbraco.Cms.Core.Security
@inject IMemberManager MemberManager
@{
var member = await MemberManager.GetCurrentMemberAsync();
}
<script>
@if (member != null)
{
<text>
fbq('init', 'YOUR_PIXEL_ID', {
em: '@member.Email?.ToLowerInvariant()',
fn: '@member.Name?.Split(' ').FirstOrDefault()?.ToLowerInvariant()',
ln: '@member.Name?.Split(' ').LastOrDefault()?.ToLowerInvariant()'
});
</text>
}
else
{
<text>
fbq('init', 'YOUR_PIXEL_ID');
</text>
}
fbq('track', 'PageView');
</script>
Method 3: IIS Application-Level Integration
Create Meta Pixel HTTP Module
MetaPixelModule.cs:
using System;
using System.Web;
using System.Text;
namespace YourProject.Modules
{
public class MetaPixelModule : IHttpModule
{
private const string PixelId = "YOUR_PIXEL_ID";
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += OnPreRequestHandlerExecute;
}
private void OnPreRequestHandlerExecute(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
HttpContext context = app.Context;
if (context.Response.ContentType == "text/html")
{
context.Response.Filter = new MetaPixelFilter(
context.Response.Filter,
PixelId
);
}
}
public void Dispose() { }
}
public class MetaPixelFilter : System.IO.Stream
{
private System.IO.Stream _responseStream;
private string _pixelId;
public MetaPixelFilter(System.IO.Stream stream, string pixelId)
{
_responseStream = stream;
_pixelId = pixelId;
}
public override void Write(byte[] buffer, int offset, int count)
{
string html = Encoding.UTF8.GetString(buffer, offset, count);
string pixelScript = $@"
<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>
";
html = html.Replace("</head>", pixelScript + "</head>");
byte[] data = Encoding.UTF8.GetBytes(html);
_responseStream.Write(data, 0, data.Length);
}
// Required abstract members implementation
public override bool CanRead => _responseStream.CanRead;
public override bool CanSeek => _responseStream.CanSeek;
public override bool CanWrite => _responseStream.CanWrite;
public override long Length => _responseStream.Length;
public override long Position
{
get => _responseStream.Position;
set => _responseStream.Position = value;
}
public override void Flush() => _responseStream.Flush();
public override int Read(byte[] buffer, int offset, int count)
=> _responseStream.Read(buffer, offset, count);
public override long Seek(long offset, System.IO.SeekOrigin origin)
=> _responseStream.Seek(offset, origin);
public override void SetLength(long value)
=> _responseStream.SetLength(value);
}
}
Register in Web.config
For IIS Integrated Pipeline:
<configuration>
<system.webServer>
<modules>
<add name="MetaPixelModule"
type="YourProject.Modules.MetaPixelModule, YourProject" />
</modules>
</system.webServer>
</configuration>
Enhanced Umbraco Integration
Track Umbraco Member Data
@using Umbraco.Cms.Core.Security
@using Microsoft.AspNetCore.Http
@inject IMemberManager MemberManager
@inject IHttpContextAccessor HttpContextAccessor
@{
var member = await MemberManager.GetCurrentMemberAsync();
}
<script>
@if (member != null)
{
var email = member.Email;
var firstName = member.Name?.Split(' ').FirstOrDefault();
var lastName = member.Name?.Split(' ').Skip(1).FirstOrDefault();
var phone = member.GetValue<string>("phone");
var city = member.GetValue<string>("city");
var state = member.GetValue<string>("state");
var zip = member.GetValue<string>("zipCode");
var country = member.GetValue<string>("country");
<text>
fbq('init', 'YOUR_PIXEL_ID', {
em: '@email?.ToLowerInvariant()',
fn: '@firstName?.ToLowerInvariant()',
ln: '@lastName?.ToLowerInvariant()',
ph: '@phone',
ct: '@city?.ToLowerInvariant()',
st: '@state?.ToLowerInvariant()',
zp: '@zip',
country: '@country?.ToLowerInvariant()'
});
</text>
}
else
{
<text>
fbq('init', 'YOUR_PIXEL_ID');
</text>
}
fbq('track', 'PageView');
</script>
Track Content Type and Template
<script>
fbq('trackCustom', 'UmbracoPageView', {
content_type: '@Model?.ContentType.Alias',
content_name: '@Model?.Name',
content_id: '@Model?.Id',
template: '@ViewData["TemplateAlias"]'
});
</script>
Conditional Loading by Environment
@inject Microsoft.Extensions.Hosting.IHostEnvironment HostEnvironment
@if (HostEnvironment.IsProduction())
{
@await Html.PartialAsync("~/Views/Partials/Analytics/MetaPixel.cshtml")
}
Performance Optimization
Preconnect to Facebook Domains
<head>
<link rel="preconnect" href="https://connect.facebook.net">
<link rel="dns-prefetch" href="https://connect.facebook.net">
@await Html.PartialAsync("~/Views/Partials/Analytics/MetaPixel.cshtml")
</head>
Defer Loading After Page Load
<script>
// Defer Meta Pixel until after page load
window.addEventListener('load', function() {
!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>
IIS-Specific Configuration
Enable IIS Compression
Web.config:
<configuration>
<system.webServer>
<urlCompression doStaticCompression="true" doDynamicCompression="true" />
<httpCompression>
<dynamicTypes>
<add mimeType="application/javascript" enabled="true" />
<add mimeType="text/javascript" enabled="true" />
</dynamicTypes>
</httpCompression>
</system.webServer>
</configuration>
Set Content Security Policy
Allow Meta Pixel domains:
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Content-Security-Policy"
value="script-src 'self' 'unsafe-inline' https://connect.facebook.net; img-src 'self' https://www.facebook.com;" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
Multi-Pixel Implementation
Track Multiple Pixels
@{
var primaryPixelId = "PRIMARY_PIXEL_ID";
var secondaryPixelId = "SECONDARY_PIXEL_ID";
}
<script>
// Initialize both pixels
fbq('init', '@primaryPixelId');
fbq('init', '@secondaryPixelId');
// Track PageView for both
fbq('track', 'PageView');
</script>
Track Specific Pixels for Events
<script>
// Track only on primary pixel
fbq('trackSingle', '@primaryPixelId', 'Lead', {
content_name: 'Newsletter Signup'
});
// Track on both pixels
fbq('track', 'CompleteRegistration');
</script>
Validation and Testing
Use Meta Pixel Helper
- Install Meta Pixel Helper Chrome extension
- Navigate to your Umbraco site
- Click extension icon
- Verify:
- Pixel detected
- PageView event fires
- No errors shown
- Advanced matching parameters present (if configured)
Test Events Manager
- Navigate to Meta Events Manager
- Select your Pixel
- Click Test Events
- Enter your website URL
- Click Open Website
- Verify events appear in Test Events tab
Browser DevTools Testing
- Open DevTools → Console
- Type:
fbqand press Enter - Verify fbq function exists
- Type:
fbq('track', 'PageView')to manually fire event - Check Network tab for requests to
facebook.com/tr
Common Issues
Pixel Not Firing
Cause: Incorrect Pixel ID or syntax error Solution:
- Verify Pixel ID is correct (16 digits)
- Check browser console for JavaScript errors
- Ensure script is in
<head>section - Clear browser cache
Duplicate Events
Cause: Multiple Pixel implementations Solution:
- Search codebase for duplicate
fbqreferences - Remove redundant partial views
- Check for package + manual implementation conflict
Umbraco Cache Issues
Cause: Cache not cleared after code changes Solution:
# Clear Umbraco cache
Remove-Item -Path "App_Data\TEMP\*" -Recurse -Force
IIS Module Not Working
Cause: Module not registered or wrong pipeline mode Solution:
- Verify Web.config registration
- Check IIS application pool mode
- Restart IIS:
iisreset
Content Security Policy Blocking
Cause: CSP header blocks Meta Pixel Solution:
<add name="Content-Security-Policy"
value="script-src 'self' 'unsafe-inline' https://connect.facebook.net; connect-src https://www.facebook.com;" />
GDPR and Privacy Compliance
Implement Consent Management
<script>
// Disable automatic initialization
fbq('consent', 'revoke');
// Wait for user consent
function enableMetaPixel() {
fbq('consent', 'grant');
fbq('track', 'PageView');
}
// Call enableMetaPixel() when user accepts cookies
document.getElementById('accept-cookies').addEventListener('click', function() {
enableMetaPixel();
});
</script>
Limited Data Use (LDU)
For California privacy compliance:
<script>
fbq('dataProcessingOptions', ['LDU'], 1, 1000); // California, USA
fbq('init', 'YOUR_PIXEL_ID');
fbq('track', 'PageView');
</script>
Next Steps
- Meta Pixel Event Tracking - Track custom events
- Troubleshooting Tracking Issues - Debug Pixel problems
- GTM Setup - Implement Google Tag Manager