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:
- Go to Events Manager → Your Pixel
- Click Test Events tab
- Enter your store URL
- Perform actions and watch events appear
- 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
Respect Customer Consent
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
- Meta Pixel Setup - Install Meta Pixel
- GTM Data Layer - Use Shopify data layer with GTM
- Events Not Firing - Troubleshoot tracking
For general Meta Pixel concepts, see Meta Pixel Event Guide.