Drupal Meta Pixel Integration | Blue Frog Docs

Drupal Meta Pixel Integration

Integrate Meta Pixel with Drupal for Facebook and Instagram advertising.

Drupal Meta Pixel Integration

Complete guide to setting up Meta Pixel (Facebook Pixel) on your Drupal site for conversion tracking and audience building.

Overview

Meta Pixel (formerly Facebook Pixel) is a powerful analytics tool that helps you measure the effectiveness of your advertising by understanding the actions people take on your Drupal website. This comprehensive guide covers everything from basic installation to advanced Conversions API implementation specific to Drupal.

Why Meta Pixel for Drupal?

Meta Pixel enables powerful advertising capabilities:

  • Conversion Tracking: Measure ad effectiveness across Facebook and Instagram
  • Custom Audiences: Retarget site visitors based on their behavior
  • Lookalike Audiences: Find similar customers to your best converters
  • Dynamic Ads: Show personalized product ads from your Drupal Commerce catalog
  • Attribution: Understand customer journey across touchpoints
  • Optimization: Improve ad delivery to people likely to take action

Installation Methods

The Meta Pixel module provides the most robust implementation for Drupal.

Installation Steps

  1. Install the Module
composer require drupal/meta_pixel
drush en meta_pixel -y
  1. Configure Module Settings

Navigate to: Configuration > System > Meta Pixel Settings (/admin/config/system/meta-pixel)

  1. Enter Your Pixel ID

Find your Pixel ID in Facebook Events Manager:

  • Go to Facebook Events Manager
  • Select your pixel
  • Copy the Pixel ID (15-16 digit number)
  • Paste into Drupal configuration
  1. Configure Event Tracking

Enable automatic events:

  • PageView (automatically tracked on all pages)
  • ViewContent (tracked on node pages)
  • Search (tracked on search results)
  1. Clear Cache
drush cr

Module Features

  • Automatic PageView tracking on all pages
  • Advanced Matching for improved attribution
  • Consent Management integration with Cookie Consent modules
  • Event parameters configuration per content type
  • User role exclusions (exclude admin users from tracking)
  • Custom event mapping through hook system

Method 2: Google Tag Manager

If you're already using GTM on Drupal, this is an efficient approach.

Implementation Steps

  1. Install Google Tag Manager Module
composer require drupal/google_tag
drush en google_tag -y
  1. Configure GTM Container

Navigate to: Configuration > System > Google Tag Manager (/admin/config/system/google_tag)

  1. Create Meta Pixel Tag in GTM

In your GTM container:

  • Tag Type: Custom HTML
  • HTML content:
<!-- 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', '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>
<!-- End Meta Pixel Code -->
  • Trigger: All Pages
  • Replace YOUR_PIXEL_ID with your actual Pixel ID
  1. Configure Data Layer Events

Create additional tags for specific events using Drupal's data layer variables.

Method 3: Manual Template Implementation

For complete control, add the pixel directly to your Drupal theme.

Implementation Steps

  1. Create Preprocess Hook

Add to your theme's THEME_NAME.theme file:

<?php

/**
 * Implements hook_page_attachments_alter().
 */
function THEME_NAME_page_attachments_alter(array &$attachments) {
  // Get pixel ID from configuration.
  $config = \Drupal::config('system.site');
  $pixel_id = $config->get('meta_pixel_id');

  if ($pixel_id && !\Drupal::currentUser()->hasPermission('bypass meta pixel')) {
    $attachments['#attached']['html_head'][] = [
      [
        '#type' => 'html_tag',
        '#tag' => 'script',
        '#value' => "
          !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', '$pixel_id');
          fbq('track', 'PageView');
        ",
      ],
      'meta_pixel_script',
    ];
  }
}
  1. Store Configuration

Create a custom module or use Settings.php:

// In settings.php
$config['system.site']['meta_pixel_id'] = 'YOUR_PIXEL_ID';

Standard Events Implementation

PageView Event

Automatically tracked with base pixel. No additional code needed.

ViewContent Event

Track when users view content (nodes):

// Add to node.html.twig or via JavaScript
fbq('track', 'ViewContent', {
  content_name: '{{ node.title.value }}',
  content_category: '{{ node.bundle }}',
  content_ids: ['{{ node.id }}'],
  content_type: 'product'
});

Lead Event

Track form submissions using Form API:

/**
 * Implements hook_form_alter().
 */
function THEME_NAME_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if ($form_id == 'contact_message_feedback_form') {
    $form['#attached']['library'][] = 'THEME_NAME/meta-pixel-lead';
    $form['actions']['submit']['#ajax'] = [
      'callback' => 'THEME_NAME_lead_tracking_callback',
    ];
  }
}

/**
 * Ajax callback for lead tracking.
 */
function THEME_NAME_lead_tracking_callback(array &$form, FormStateInterface $form_state) {
  $response = new AjaxResponse();
  $response->addCommand(new InvokeCommand(NULL, 'fbq', ['track', 'Lead']));
  return $response;
}

AddToCart Event (Drupal Commerce)

For Drupal Commerce installations:

/**
 * Implements hook_commerce_add_to_cart().
 */
function THEME_NAME_commerce_add_to_cart($order_item, $order, $cart_session) {
  $product_variation = $order_item->getPurchasedEntity();
  $product = $product_variation->getProduct();

  $tracking_data = [
    'content_name' => $product->getTitle(),
    'content_ids' => [$product_variation->getSku()],
    'content_type' => 'product',
    'value' => $product_variation->getPrice()->getNumber(),
    'currency' => $product_variation->getPrice()->getCurrencyCode(),
  ];

  // Attach as drupalSettings for JavaScript to consume
  \Drupal::service('renderer')->addCacheableDependency($tracking_data);
}

JavaScript component:

(function ($, Drupal, drupalSettings) {
  Drupal.behaviors.metaPixelAddToCart = {
    attach: function (context, settings) {
      $('.add-to-cart-form', context).once('meta-pixel-cart').on('submit', function() {
        if (typeof fbq !== 'undefined' && settings.metaPixelCartData) {
          fbq('track', 'AddToCart', settings.metaPixelCartData);
        }
      });
    }
  };
})(jQuery, Drupal, drupalSettings);

InitiateCheckout Event

/**
 * Track checkout initiation.
 */
function THEME_NAME_preprocess_page(&$variables) {
  $route_name = \Drupal::routeMatch()->getRouteName();

  if ($route_name === 'commerce_checkout.form') {
    $variables['#attached']['drupalSettings']['metaPixel']['initiateCheckout'] = TRUE;
  }
}

Purchase Event

Track completed orders:

/**
 * Implements hook_commerce_order_update().
 */
function THEME_NAME_commerce_order_update(OrderInterface $order) {
  if ($order->getState()->getId() === 'completed') {
    $order_items = $order->getItems();
    $content_ids = [];

    foreach ($order_items as $item) {
      $content_ids[] = $item->getPurchasedEntity()->getSku();
    }

    $purchase_data = [
      'value' => $order->getTotalPrice()->getNumber(),
      'currency' => $order->getTotalPrice()->getCurrencyCode(),
      'content_ids' => $content_ids,
      'content_type' => 'product',
      'num_items' => count($order_items),
    ];

    // Store in session for confirmation page rendering
    \Drupal::service('session')->set('meta_pixel_purchase', $purchase_data);
  }
}

Advanced Matching

Improve attribution by sending hashed customer information:

fbq('init', 'YOUR_PIXEL_ID', {
  em: '{{ user.mail|lower|hash('sha256') }}',
  fn: '{{ user.field_first_name.value|lower|hash('sha256') }}',
  ln: '{{ user.field_last_name.value|lower|hash('sha256') }}',
  ct: '{{ user.field_city.value|lower|hash('sha256') }}',
  st: '{{ user.field_state.value|lower|hash('sha256') }}',
  zp: '{{ user.field_zip.value|hash('sha256') }}'
});

Create a Twig filter for SHA256 hashing:

/**
 * Implements hook_twig_extension().
 */
class HashTwigExtension extends \Twig\Extension\AbstractExtension {
  public function getFilters() {
    return [
      new \Twig\TwigFilter('hash', [$this, 'hashValue']),
    ];
  }

  public function hashValue($value, $algorithm = 'sha256') {
    return hash($algorithm, trim(strtolower($value)));
  }
}

Conversions API (Server-Side Tracking)

CAPI provides more reliable tracking that isn't affected by browser restrictions.

Installation

  1. Install Facebook Business SDK
composer require facebook/php-business-sdk
  1. Create Custom Module

Create meta_pixel_capi module:

<?php

namespace Drupal\meta_pixel_capi\EventSubscriber;

use FacebookAds\Api;
use FacebookAds\Object\ServerSide\Event;
use FacebookAds\Object\ServerSide\EventRequest;
use FacebookAds\Object\ServerSide\UserData;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ConversionsApiSubscriber implements EventSubscriberInterface {

  public function sendEvent($event_name, $event_data = []) {
    $access_token = \Drupal::config('meta_pixel_capi.settings')->get('access_token');
    $pixel_id = \Drupal::config('meta_pixel_capi.settings')->get('pixel_id');

    Api::init(null, null, $access_token);

    $user_data = (new UserData())
      ->setEmail($event_data['email'])
      ->setClientIpAddress($_SERVER['REMOTE_ADDR'])
      ->setClientUserAgent($_SERVER['HTTP_USER_AGENT'])
      ->setFbc($_COOKIE['_fbc'] ?? null)
      ->setFbp($_COOKIE['_fbp'] ?? null);

    $event = (new Event())
      ->setEventName($event_name)
      ->setEventTime(time())
      ->setEventSourceUrl(\Drupal::request()->getUri())
      ->setUserData($user_data);

    if (isset($event_data['value'])) {
      $event->setCustomData([
        'value' => $event_data['value'],
        'currency' => $event_data['currency'] ?? 'USD',
      ]);
    }

    $request = (new EventRequest($pixel_id))
      ->setEvents([$event]);

    $response = $request->execute();

    return $response;
  }
}
  1. Track Purchase via CAPI
/**
 * Send purchase event to Conversions API.
 */
function meta_pixel_capi_commerce_order_update(OrderInterface $order) {
  if ($order->getState()->getId() === 'completed') {
    $subscriber = \Drupal::service('meta_pixel_capi.subscriber');

    $subscriber->sendEvent('Purchase', [
      'email' => $order->getEmail(),
      'value' => $order->getTotalPrice()->getNumber(),
      'currency' => $order->getTotalPrice()->getCurrencyCode(),
    ]);
  }
}

Drupal Commerce Integration

Product Catalog Feed

Create a dynamic catalog for Dynamic Ads:

/**
 * Implements hook_page_attachments().
 */
function THEME_NAME_page_attachments(array &$page) {
  $route_match = \Drupal::routeMatch();

  if ($route_match->getRouteName() === 'entity.commerce_product.canonical') {
    $product = $route_match->getParameter('commerce_product');
    $variation = $product->getDefaultVariation();

    if ($variation) {
      $page['#attached']['html_head'][] = [
        [
          '#tag' => 'meta',
          '#attributes' => [
            'property' => 'product:retailer_item_id',
            'content' => $variation->getSku(),
          ],
        ],
        'meta_product_id',
      ];

      $page['#attached']['html_head'][] = [
        [
          '#tag' => 'meta',
          '#attributes' => [
            'property' => 'product:price:amount',
            'content' => $variation->getPrice()->getNumber(),
          ],
        ],
        'meta_product_price',
      ];

      $page['#attached']['html_head'][] = [
        [
          '#tag' => 'meta',
          '#attributes' => [
            'property' => 'product:price:currency',
            'content' => $variation->getPrice()->getCurrencyCode(),
          ],
        ],
        'meta_product_currency',
      ];
    }
  }
}

Troubleshooting

Pixel Not Firing

Check Module Status:

drush pml | grep meta_pixel

Verify Pixel ID:

drush config:get meta_pixel.settings pixel_id

Check for JavaScript Errors: Open browser console and look for errors related to fbq.

Verify User Permissions: Ensure you're not logged in as admin if admin exclusion is enabled.

Events Not Showing in Events Manager

Test Events: Use Meta's Test Events tool in Events Manager to verify events are being received.

Check Browser Console:

// Test if fbq is loaded
console.log(typeof fbq);

// Manually fire test event
fbq('track', 'PageView');

Enable Debug Mode:

// Add to pixel initialization
fbq('init', 'YOUR_PIXEL_ID', {}, {
  debug: true
});

Conversions API Issues

Test API Connection:

$response = $request->execute();
\Drupal::logger('meta_pixel_capi')->info('Response: @response', [
  '@response' => print_r($response, TRUE),
]);

Common Error Codes:

  • Error 100: Invalid access token - regenerate in Events Manager
  • Error 190: Access token expired - create new token
  • Error 2: Invalid parameter - check event data formatting

Cache Issues

Clear All Caches:

drush cr

Disable Caching for Testing:

// In development.services.yml
parameters:
  twig.config:
    cache: false

Privacy and Compliance

GDPR Compliance

Integrate with Cookie Consent module:

/**
 * Implements hook_page_attachments_alter().
 */
function THEME_NAME_page_attachments_alter(array &$attachments) {
  // Only load pixel if consent given
  if (\Drupal::service('cookie_consent')->hasConsent('marketing')) {
    // Add Meta Pixel
  }
}

Data Processing Options

For California Consumer Privacy Act (CCPA) compliance:

fbq('dataProcessingOptions', ['LDU'], 1, 1000);

Performance Optimization

Lazy Loading

Load pixel after page load:

window.addEventListener('load', function() {
  // Load Meta Pixel
  !function(f,b,e,v,n,t,s){...}
});

Conditional Loading

Only load on specific pages:

function THEME_NAME_page_attachments_alter(array &$attachments) {
  $route_name = \Drupal::routeMatch()->getRouteName();

  $pixel_routes = [
    'entity.commerce_product.canonical',
    'commerce_checkout.form',
    'commerce_payment.checkout.return',
  ];

  if (in_array($route_name, $pixel_routes)) {
    // Add pixel only on these routes
  }
}

Testing and Validation

Meta Pixel Helper

Install the Meta Pixel Helper Chrome extension.

What to Check:

  • Pixel fires on every page
  • Correct Pixel ID is displayed
  • Events fire with proper parameters
  • No errors or warnings

Test Events Tool

In Facebook Events Manager:

  1. Navigate to Test Events tab
  2. Enter your website URL
  3. Browse your site
  4. Verify events appear in real-time

Event Match Quality

Monitor in Events Manager:

  1. Go to Data Sources > Your Pixel
  2. Click Event Match Quality
  3. Target score: 5.0+ out of 10
  4. Improve by implementing Advanced Matching

Best Practices

  1. Use Module When Possible - The Meta Pixel module provides the most maintainable solution
  2. Implement CAPI - Server-side tracking is more reliable than browser-only
  3. Enable Advanced Matching - Improves attribution accuracy
  4. Exclude Admin Users - Prevent internal traffic from skewing data
  5. Test Before Launch - Use Test Events to verify implementation
  6. Monitor Event Match Quality - Aim for scores above 5.0
  7. Document Custom Events - Keep a log of event implementations
  8. Regular Audits - Quarterly review of tracking accuracy
// SYS.FOOTER