Meta Pixel Event Tracking for Shopify | Blue Frog Docs

Meta Pixel Event Tracking for Shopify

Track Shopify-specific Meta Pixel events including standard and custom events for better Facebook and Instagram advertising.

Meta Pixel Event Tracking for Shopify

Configure Meta Pixel events for your Shopify store to track customer behavior and optimize Facebook and Instagram advertising campaigns.

Standard Meta Pixel Events

Meta Pixel provides standard events optimized for ad delivery and conversion tracking.

Ecommerce Standard Events

Event Name When to Fire Use Case
ViewContent Product page view Product catalog ads
AddToCart Item added to cart Cart abandonment, retargeting
InitiateCheckout Checkout begins Checkout funnel optimization
Purchase Order completed Conversion tracking, ROAS
Search Search performed Search-based audiences
AddToWishlist Wishlist addition Engagement audiences

Engagement Standard Events

Event Name When to Fire Use Case
Lead Form submission Lead generation campaigns
CompleteRegistration Account created Registration conversion
Contact Contact form submitted Customer inquiries
Subscribe Newsletter signup Email list growth

ViewContent Event

Track when customers view product detail pages.

Manual Implementation

Add to product template (product.liquid or product section):

<script>
  fbq('track', 'ViewContent', {
    content_name: '{{ product.title | escape }}',
    content_category: '{{ product.type | escape }}',
    content_ids: ['{{ product.id }}'],
    content_type: 'product',
    value: {{ product.selected_or_first_available_variant.price | money_without_currency }},
    currency: '{{ cart.currency.iso_code }}'
  });
</script>

Using GTM + Shopify Data Layer

1. Create Trigger:

  • Type: Custom Event
  • Event name: product_viewed
  • Name: CE - Product Viewed

2. Create Variables:

Product ID:

// Custom JavaScript Variable
function() {
  const dl = window.dataLayer || [];
  for (let i = dl.length - 1; i >= 0; i--) {
    if (dl[i].ecommerce && dl[i].ecommerce.detail) {
      return [dl[i].ecommerce.detail.products[0].id];
    }
  }
  return [];
}

Product Value:

function() {
  const dl = window.dataLayer || [];
  for (let i = dl.length - 1; i >= 0; i--) {
    if (dl[i].ecommerce && dl[i].ecommerce.detail) {
      return parseFloat(dl[i].ecommerce.detail.products[0].price);
    }
  }
  return 0;
}

3. Create Tag:

  • Type: Custom HTML
  • HTML:
<script>
  fbq('track', 'ViewContent', {
    content_name: {{Product Name}},
    content_category: {{Product Category}},
    content_ids: {{Product IDs Array}},
    content_type: 'product',
    value: {{Product Value}},
    currency: {{Currency}}
  });
</script>
  • Trigger: CE - Product Viewed

AddToCart Event

Track when items are added to cart.

Manual Implementation (AJAX Cart)

For themes with AJAX cart (most modern themes including Dawn):

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Listen for add to cart button clicks
  const addToCartForms = document.querySelectorAll('form[action*="/cart/add"]');

  addToCartForms.forEach(function(form) {
    form.addEventListener('submit', function(e) {
      const formData = new FormData(form);
      const variantId = formData.get('id');
      const quantity = parseInt(formData.get('quantity')) || 1;

      // Get variant price
      fetch('/variants/' + variantId + '.js')
        .then(response => response.json())
        .then(variant => {
          fbq('track', 'AddToCart', {
            content_name: '{{ product.title | escape }}',
            content_ids: ['{{ product.id }}'],
            content_type: 'product',
            value: (variant.price / 100) * quantity,
            currency: '{{ cart.currency.iso_code }}'
          });
        });
    });
  });
});
</script>

Using GTM + Shopify Data Layer

1. Create Trigger:

  • Type: Custom Event
  • Event name: product_added_to_cart

2. Create Variables:

Add to Cart Value:

function() {
  const dl = window.dataLayer || [];
  for (let i = dl.length - 1; i >= 0; i--) {
    if (dl[i].ecommerce && dl[i].ecommerce.add) {
      const products = dl[i].ecommerce.add.products;
      return products.reduce(function(sum, p) {
        return sum + (parseFloat(p.price) * parseInt(p.quantity));
      }, 0);
    }
  }
  return 0;
}

3. Create Tag:

<script>
  fbq('track', 'AddToCart', {
    content_ids: {{Add to Cart - Product IDs}},
    content_type: 'product',
    value: {{Add to Cart - Value}},
    currency: {{Currency}}
  });
</script>

InitiateCheckout Event

Track when customers begin checkout.

Implementation (Cart Page)

Add to cart template or checkout button:

<script>
document.querySelector('[name="checkout"]').addEventListener('click', function() {
  fbq('track', 'InitiateCheckout', {
    content_ids: [
      {% for item in cart.items %}
        '{{ item.product_id }}'{% unless forloop.last %},{% endunless %}
      {% endfor %}
    ],
    content_type: 'product',
    value: {{ cart.total_price | money_without_currency }},
    currency: '{{ cart.currency.iso_code }}',
    num_items: {{ cart.item_count }}
  });
});
</script>

Shopify Plus: Checkout.liquid

For Plus stores, fire on first checkout step:

{% if checkout.step == 'contact_information' %}
<script>
  fbq('track', 'InitiateCheckout', {
    content_ids: [
      {% for line_item in checkout.line_items %}
        '{{ line_item.product_id }}'{% unless forloop.last %},{% endunless %}
      {% endfor %}
    ],
    content_type: 'product',
    value: {{ checkout.total_price | money_without_currency }},
    currency: '{{ checkout.currency }}',
    num_items: {{ checkout.line_items.size }}
  });
</script>
{% endif %}

Purchase Event

Track completed orders (all stores).

Order Status Page Implementation

Go to: Settings → Checkout → Order status page → Additional scripts

<script>
  fbq('track', 'Purchase', {
    content_ids: [
      {% for line_item in line_items %}
        '{{ line_item.product_id }}'{% unless forloop.last %},{% endunless %}
      {% endfor %}
    ],
    content_type: 'product',
    content_name: 'Order {{ order.order_number }}',
    value: {{ total_price | money_without_currency }},
    currency: '{{ currency }}',
    num_items: {{ line_items.size }}
  });
</script>

Prevent Duplicate Purchase Events

Add transaction deduplication:

<script>
  // Check if already tracked
  const transactionId = '{{ order.order_number }}';

  if (!sessionStorage.getItem('fb_purchase_' + transactionId)) {
    fbq('track', 'Purchase', {
      content_ids: [
        {% for line_item in line_items %}
          '{{ line_item.product_id }}'{% unless forloop.last %},{% endunless %}
        {% endfor %}
      ],
      content_type: 'product',
      value: {{ total_price | money_without_currency }},
      currency: '{{ currency }}'
    });

    sessionStorage.setItem('fb_purchase_' + transactionId, 'true');
  }
</script>

Search Event

Track site searches.

Implementation

Add to search results page (search.liquid):

<script>
  fbq('track', 'Search', {
    search_string: '{{ search.terms | escape }}',
    content_ids: [
      {% for item in search.results limit: 10 %}
        {% if item.object_type == 'product' %}
          '{{ item.id }}'{% unless forloop.last %},{% endunless %}
        {% endif %}
      {% endfor %}
    ],
    content_type: 'product'
  });
</script>

AddToWishlist Event

Track wishlist additions (if your theme supports wishlists).

Implementation

<script>
// Attach to wishlist button click
document.querySelectorAll('.wishlist-button').forEach(function(button) {
  button.addEventListener('click', function() {
    const productId = this.getAttribute('data-product-id');
    const productName = this.getAttribute('data-product-name');
    const productPrice = parseFloat(this.getAttribute('data-product-price'));

    fbq('track', 'AddToWishlist', {
      content_name: productName,
      content_ids: [productId],
      content_type: 'product',
      value: productPrice,
      currency: '{{ cart.currency.iso_code }}'
    });
  });
});
</script>

Custom Events

Create custom events for Shopify-specific interactions.

Newsletter Signup

<script>
document.querySelector('#newsletter-form').addEventListener('submit', function(e) {
  fbq('track', 'Subscribe', {
    content_name: 'Newsletter',
    value: 0,
    currency: '{{ cart.currency.iso_code }}'
  });

  // Or use custom event
  fbq('trackCustom', 'NewsletterSignup', {
    location: '{{ template.name }}'
  });
});
</script>

Account Creation

Add to account registration confirmation page:

{% if customer %}
<script>
  fbq('track', 'CompleteRegistration', {
    content_name: 'Account Registration',
    status: 'completed'
  });
</script>
{% endif %}

Contact Form Submission

<script>
document.querySelector('#contact-form').addEventListener('submit', function() {
  fbq('track', 'Contact', {
    content_name: 'Contact Form',
    content_category: 'Support'
  });
});
</script>

Product Review Submitted

<script>
// After review form submission
fbq('trackCustom', 'ProductReview', {
  content_ids: ['{{ product.id }}'],
  content_name: '{{ product.title | escape }}',
  rating: ratingValue // From your review system
});
</script>

Size Guide Viewed

<script>
document.querySelector('.size-guide-link').addEventListener('click', function() {
  fbq('trackCustom', 'SizeGuideView', {
    content_ids: ['{{ product.id }}'],
    content_type: 'product'
  });
});
</script>

Discount Code Applied

{% if cart.discount_applications.size > 0 %}
<script>
  fbq('trackCustom', 'DiscountApplied', {
    content_name: '{{ cart.discount_applications[0].title }}',
    value: {{ cart.total_discount | money_without_currency }},
    currency: '{{ cart.currency.iso_code }}'
  });
</script>
{% endif %}

Event Parameters

Standard Parameters

All events should include:

fbq('track', 'EventName', {
  content_ids: ['123'],        // Required: Product IDs
  content_type: 'product',     // Required: Usually 'product'
  content_name: 'Product Name', // Recommended
  value: 29.99,                // Recommended: Numeric only
  currency: 'USD'              // Required with value
});

Additional Parameters

Ecommerce-Specific:

{
  content_category: 'Apparel',
  num_items: 2,
  predicted_ltv: 150.00,
  search_string: 'blue shirt',
  status: 'completed'
}

Content Parameters:

{
  content_ids: ['123', '456'],  // Array of product IDs
  contents: [                    // Detailed item info
    {id: '123', quantity: 2},
    {id: '456', quantity: 1}
  ]
}

Advanced Matching Parameters

Send hashed customer data for better attribution:

<script>
{% if customer %}
  fbq('init', 'YOUR_PIXEL_ID', {
    em: '{{ customer.email | downcase }}',
    fn: '{{ customer.first_name | downcase }}',
    ln: '{{ customer.last_name | downcase }}',
    ph: '{{ customer.phone }}',
    ct: '{{ customer.default_address.city | downcase }}',
    st: '{{ customer.default_address.province_code | downcase }}',
    zp: '{{ customer.default_address.zip }}',
    country: '{{ customer.default_address.country_code | downcase }}'
  });
{% else %}
  fbq('init', 'YOUR_PIXEL_ID');
{% endif %}
</script>

Note: Meta automatically hashes this data client-side for privacy.

Event Value Best Practices

1. Use Numeric Values Only

<!-- Correct -->
value: {{ product.price | money_without_currency }}

<!-- Wrong -->
value: '{{ product.price }}'  // Includes currency symbol

2. Include Tax and Shipping in Purchase Value

value: {{ total_price | money_without_currency }},  // Full order total

3. Multiply Price by Quantity

value: productPrice * quantity,

4. Use Consistent Currency Codes

currency: '{{ cart.currency.iso_code }}'  // USD, EUR, GBP, etc.

Testing Events

1. Meta Pixel Helper

Install Meta Pixel Helper Chrome extension:

  • Navigate to your store
  • Check icon shows events firing
  • Green = Success
  • Yellow = Warning
  • Red = Error

2. Meta Events Manager

Real-time event testing:

  1. Go to Events Manager → Your Pixel
  2. Click Test Events tab
  3. Enter your store URL
  4. Perform actions and watch events appear
  5. Verify parameters are correct

3. Test Event Browser

Use Meta's test event feature:

fbq('track', 'Purchase', {
  // parameters
}, {
  eventID: 'unique_event_id_123'  // For deduplication with CAPI
});

Common Issues

Events Fire Multiple Times

Cause: Multiple pixel implementations or page reloads.

Fix:

  • Remove duplicate Meta Pixel code
  • Use event deduplication
  • Check for multiple tracking apps

Missing Parameters

Cause: Incorrect Liquid syntax or unavailable data.

Fix:

  • Verify objects exist in current template context
  • Use safe filters: | escape, | downcase
  • Check for empty values and provide defaults

Value is $0 or Incorrect

Cause: Currency format or calculation error.

Fix:

<!-- Always use money_without_currency -->
{{ price | money_without_currency }}

<!-- Shopify prices are in cents in some contexts -->
{{ variant.price / 100 }}

Events Not Attributed to Ads

Cause: Missing eventID for CAPI deduplication or browser tracking prevention.

Solution: Implement Conversions API (CAPI) for server-side events.

Privacy Compliance

document.addEventListener('visitorConsentCollected', function(event) {
  const consent = event.detail;

  if (consent.marketing) {
    // Initialize and fire events only after consent
    fbq('init', 'YOUR_PIXEL_ID');
    fbq('track', 'PageView');
  }
});

Limited Data Use (LDU)

For California CCPA compliance:

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

GDPR Compliance

Configure in Meta Events Manager under Data Processing Options.

Next Steps

For general Meta Pixel concepts, see Meta Pixel Event Guide.

// SYS.FOOTER