Meta Pixel Event Tracking on Wix | Blue Frog Docs

Meta Pixel Event Tracking on Wix

Implement custom events and ecommerce tracking for Meta Pixel on Wix using Velo and custom code.

Meta Pixel Event Tracking on Wix

This guide covers implementing custom Meta Pixel events on Wix, including standard events, custom conversions, and ecommerce tracking for Wix Stores.

Prerequisites

  • Meta Pixel installed (see setup guide)
  • Wix Premium plan (for custom code)
  • Velo enabled (for advanced tracking)
  • Understanding of Wix's SPA navigation

Standard Events Overview

Meta provides 17 standard events for tracking user actions:

Event Purpose Common Use Case
ViewContent Content viewed Product/blog page views
Search Search performed Site search results
AddToCart Item added to cart Wix Stores add to cart
AddToWishlist Item added to wishlist Saved for later
InitiateCheckout Checkout started Cart → Checkout
AddPaymentInfo Payment details added Checkout payment step
Purchase Purchase completed Thank you page
Lead Lead form submitted Contact forms
CompleteRegistration Account created Member signup
Contact Contact initiated Phone clicks, chat
Subscribe Newsletter signup Email subscription
StartTrial Trial started SaaS/subscription sites
Schedule Appointment scheduled Wix Bookings

Basic Event Tracking with Velo

Page Code Structure

// File: Page Code (e.g., Product Page)
import wixWindow from 'wix-window';

$w.onReady(function () {
  // Track event when ready
  trackMetaEvent('ViewContent', {
    content_name: 'Product Name',
    content_category: 'Category',
    content_type: 'product',
    value: 29.99,
    currency: 'USD'
  });
});

// Helper function
function trackMetaEvent(eventName, parameters) {
  if (window.fbq) {
    fbq('track', eventName, parameters);
  } else {
    console.warn('Meta Pixel not loaded');
  }
}

Ecommerce Events for Wix Stores

1. ViewContent (Product Page)

Track product detail page views:

// File: Product Page Code
import wixStoresFrontend from 'wix-stores-frontend';

$w.onReady(async function () {
  try {
    const product = await wixStoresFrontend.product.getProduct();

    if (window.fbq && product) {
      fbq('track', 'ViewContent', {
        content_ids: [product.sku || product.id],
        content_name: product.name,
        content_type: 'product',
        content_category: product.productType || 'General',
        value: product.price,
        currency: product.currency || 'USD'
      });
    }
  } catch (error) {
    console.error('ViewContent tracking error:', error);
  }
});

2. AddToCart

Track when items are added to cart:

import wixStoresFrontend from 'wix-stores-frontend';

$w.onReady(function () {
  $w('#addToCartButton').onClick(async () => {
    try {
      const product = await wixStoresFrontend.product.getProduct();
      const quantity = Number($w('#quantityInput').value) || 1;
      const selectedOptions = await wixStoresFrontend.product.getOptionsSelections();

      if (window.fbq) {
        fbq('track', 'AddToCart', {
          content_ids: [product.sku || product.id],
          content_name: product.name,
          content_type: 'product',
          value: product.price * quantity,
          currency: product.currency || 'USD',
          num_items: quantity,
          // Custom parameters
          content_variant: selectedOptions.map(opt => opt.selection).join(' / ') || ''
        });
      }
    } catch (error) {
      console.error('AddToCart tracking error:', error);
    }
  });
});

3. ViewCategory (Collection Page)

Track category/collection browsing:

// File: Collection Page Code
import wixStoresFrontend from 'wix-stores-frontend';

$w.onReady(async function () {
  try {
    const category = await wixStoresFrontend.category.getCategory();
    const products = await wixStoresFrontend.products.getProducts();

    if (window.fbq && products.items) {
      const contentIds = products.items
        .slice(0, 10) // First 10 products
        .map(p => p.sku || p.id);

      fbq('track', 'ViewContent', {
        content_ids: contentIds,
        content_type: 'product_group',
        content_category: category?.name || 'All Products'
      });
    }
  } catch (error) {
    console.error('ViewContent (category) error:', error);
  }
});

4. InitiateCheckout

Track checkout initiation:

// File: Cart Page or Checkout Button
import wixStoresFrontend from 'wix-stores-frontend';

$w('#checkoutButton').onClick(async () => {
  try {
    const cart = await wixStoresFrontend.cart.getCurrentCart();

    if (window.fbq && cart && cart.lineItems) {
      const contentIds = cart.lineItems.map(item => item.sku || item.productId);

      fbq('track', 'InitiateCheckout', {
        content_ids: contentIds,
        contents: cart.lineItems.map(item => ({
          id: item.sku || item.productId,
          quantity: item.quantity,
          item_price: item.price
        })),
        value: cart.subtotal,
        currency: cart.currency || 'USD',
        num_items: cart.lineItems.reduce((sum, item) => sum + item.quantity, 0)
      });
    }
  } catch (error) {
    console.error('InitiateCheckout tracking error:', error);
  }
});

5. AddPaymentInfo

Track payment information submission:

// File: Checkout Page (Payment Step)
// Note: Wix checkout is mostly closed - track when entering checkout

$w.onReady(async function () {
  const cart = await wixStoresFrontend.cart.getCurrentCart();

  // Listen for checkout widget ready (if accessible)
  setTimeout(() => {
    if (window.fbq && cart) {
      fbq('track', 'AddPaymentInfo', {
        content_ids: cart.lineItems.map(i => i.sku || i.productId),
        value: cart.subtotal,
        currency: cart.currency || 'USD'
      });
    }
  }, 2000); // Delay to ensure checkout loaded
});

6. Purchase

Track completed purchases on thank you page:

// File: Thank You Page Code
import wixLocation from 'wix-location';

$w.onReady(async function () {
  try {
    const orderId = wixLocation.query.orderId;

    if (!orderId) return;

    // Prevent duplicate tracking
    if (sessionStorage.getItem('metaPurchaseTracked_' + orderId)) {
      return;
    }

    // Fetch order details (requires backend function)
    const order = await getOrderDetails(orderId);

    if (window.fbq && order) {
      const contentIds = order.lineItems.map(item => item.sku || item.productId);

      fbq('track', 'Purchase', {
        content_ids: contentIds,
        contents: order.lineItems.map(item => ({
          id: item.sku || item.productId,
          quantity: item.quantity,
          item_price: item.price
        })),
        content_type: 'product',
        value: order.totals.total,
        currency: order.currency || 'USD',
        num_items: order.lineItems.length,
        // Additional parameters
        order_id: order.number || order._id,
        // delivery_category: 'home_delivery' // Optional
      });

      // Mark as tracked
      sessionStorage.setItem('metaPurchaseTracked_' + orderId, 'true');
    }
  } catch (error) {
    console.error('Purchase tracking error:', error);
  }
});

// Helper to fetch order details
async function getOrderDetails(orderId) {
  const { fetch } = await import('wix-fetch');
  const response = await fetch(`/api/getOrder?orderId=${orderId}`);
  return response.json();
}

Backend Code (to retrieve order):

// File: backend/http-functions.js
import { ok, notFound } from 'wix-http-functions';
import { orders } from 'wix-stores-backend';

export async function get_getOrder(request) {
  const orderId = request.query.orderId;

  if (!orderId) return notFound();

  try {
    const order = await orders.getOrder(orderId);
    return ok({ body: JSON.stringify(order) });
  } catch (error) {
    return notFound();
  }
}

Lead Generation Events

Lead Event (Form Submission)

Track contact form submissions:

// File: Page with Wix Form
$w.onReady(function () {
  $w('#contactForm').onWixFormSubmitted((event) => {
    if (window.fbq) {
      fbq('track', 'Lead', {
        content_name: 'Contact Form',
        content_category: 'Lead Generation',
        // Optional: estimated lead value
        value: 10.00,
        currency: 'USD'
      });
    }
  });
});

Subscribe Event (Newsletter)

$w('#newsletterForm').onWixFormSubmitted((event) => {
  if (window.fbq) {
    fbq('track', 'Subscribe', {
      value: 5.00, // Estimated value
      currency: 'USD',
      predicted_ltv: 50.00 // Optional: lifetime value estimate
    });
  }
});

Contact Event (Phone/Email Click)

// Track phone number clicks
$w('#phoneButton').onClick(() => {
  if (window.fbq) {
    fbq('track', 'Contact', {
      contact_method: 'phone'
    });
  }
});

// Track email link clicks
$w('#emailButton').onClick(() => {
  if (window.fbq) {
    fbq('track', 'Contact', {
      contact_method: 'email'
    });
  }
});

CompleteRegistration (Wix Members)

Track new member signups:

// File: Site Code (Global)
import wixUsers from 'wix-users';

$w.onReady(function () {
  wixUsers.onLogin((user) => {
    // Check if this is a new registration
    // (Wix doesn't expose onRegister directly)

    if (window.fbq) {
      fbq('track', 'CompleteRegistration', {
        content_name: 'Wix Member Registration',
        status: 'completed',
        value: 0.00,
        currency: 'USD'
      });
    }
  });
});

Service Business Events

Schedule Event (Wix Bookings)

Track appointment bookings:

// File: Booking Page or Site Code
import wixBookingsFrontend from 'wix-bookings-frontend';

// Listen for booking creation
wixBookingsFrontend.onBookingCreated((booking) => {
  if (window.fbq) {
    fbq('track', 'Schedule', {
      content_name: booking.serviceName,
      value: booking.price || 0,
      currency: booking.currency || 'USD',
      // Custom parameters
      booking_date: booking.startDate,
      booking_id: booking.id
    });
  }
});

Custom Events

For actions not covered by standard events, use custom events:

// Track video play
$w('#videoPlayer').onPlay(() => {
  if (window.fbq) {
    fbq('trackCustom', 'VideoPlay', {
      video_title: $w('#videoPlayer').title,
      video_url: $w('#videoPlayer').src
    });
  }
});

// Track file download
$w('#downloadButton').onClick(() => {
  if (window.fbq) {
    fbq('trackCustom', 'FileDownload', {
      file_name: 'Product Catalog 2024.pdf',
      file_type: 'pdf'
    });
  }
});

// Track chat widget open
$w('#chatButton').onClick(() => {
  if (window.fbq) {
    fbq('trackCustom', 'ChatOpened', {
      chat_location: 'homepage_hero'
    });
  }
});

Advanced Matching

Improve attribution by sending hashed user data:

// Helper to hash email (requires crypto library or Velo backend)
async function hashEmail(email) {
  const encoder = new TextEncoder();
  const data = encoder.encode(email.toLowerCase().trim());
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

// Use in init
import wixUsers from 'wix-users';

$w.onReady(async function () {
  if (wixUsers.currentUser.loggedIn) {
    const email = await wixUsers.currentUser.getEmail();
    const hashedEmail = await hashEmail(email);

    if (window.fbq) {
      fbq('init', 'YOUR_PIXEL_ID', {
        em: hashedEmail
      });
    }
  }
});

Implement via Conversions API (see below).

Conversions API (CAPI) for Wix

For improved tracking reliability, implement server-side tracking with Conversions API.

Why Use CAPI?

  • Bypass ad blockers - Server-side events aren't blocked
  • Improve attribution - More accurate data
  • iOS 14.5+ tracking - Less affected by ATT
  • Data redundancy - Combined with browser pixel

Basic CAPI Implementation

Backend Code:

// File: backend/events.js
import { fetch } from 'wix-fetch';

const PIXEL_ID = 'YOUR_PIXEL_ID';
const ACCESS_TOKEN = 'YOUR_CAPI_ACCESS_TOKEN'; // From Meta Events Manager

export async function sendMetaEvent(eventName, eventData, userData = {}) {
  const url = `https://graph.facebook.com/v18.0/${PIXEL_ID}/events`;

  const payload = {
    data: [{
      event_name: eventName,
      event_time: Math.floor(Date.now() / 1000),
      action_source: 'website',
      event_source_url: eventData.event_source_url || '',
      user_data: {
        client_ip_address: userData.ip || '',
        client_user_agent: userData.userAgent || '',
        em: userData.email ? await hashSHA256(userData.email) : undefined,
        ph: userData.phone ? await hashSHA256(userData.phone) : undefined,
        fn: userData.firstName ? await hashSHA256(userData.firstName) : undefined,
        ln: userData.lastName ? await hashSHA256(userData.lastName) : undefined,
        fbc: userData.fbclid || undefined,
        fbp: userData.fbp || undefined
      },
      custom_data: eventData.custom_data || {}
    }],
    access_token: ACCESS_TOKEN
  };

  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload)
    });

    const result = await response.json();
    return result;
  } catch (error) {
    console.error('CAPI error:', error);
    return null;
  }
}

async function hashSHA256(text) {
  // Implement SHA-256 hashing
  // Use Node.js crypto in backend
  const crypto = require('crypto');
  return crypto.createHash('sha256').update(text.toLowerCase().trim()).digest('hex');
}

Frontend Call (Purchase Example):

// File: Thank You Page
import { sendMetaEvent } from 'backend/events';
import wixLocation from 'wix-location';

$w.onReady(async function () {
  const orderId = wixLocation.query.orderId;
  const order = await getOrderDetails(orderId);

  // Send via CAPI (server-side)
  await sendMetaEvent('Purchase', {
    event_source_url: wixLocation.url,
    custom_data: {
      value: order.totals.total,
      currency: order.currency,
      content_ids: order.lineItems.map(i => i.sku || i.productId),
      content_type: 'product',
      num_items: order.lineItems.length
    }
  }, {
    ip: 'user_ip', // Get from request if possible
    userAgent: navigator.userAgent,
    email: order.buyerInfo?.email,
    fbp: getCookie('_fbp'),
    fbc: getCookie('_fbc')
  });

  // Also send browser pixel event
  fbq('track', 'Purchase', { /* ... */ });
});

function getCookie(name) {
  const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
  return match ? match[2] : null;
}

Event Deduplication

When using both Pixel and CAPI, deduplicate events:

// Browser pixel with event_id
const eventId = 'purchase_' + Date.now() + '_' + Math.random();

fbq('track', 'Purchase', {
  value: 99.99,
  currency: 'USD'
}, {
  eventID: eventId
});

// Send same eventID to CAPI
await sendMetaEvent('Purchase', {
  event_id: eventId, // Same ID for deduplication
  custom_data: {
    value: 99.99,
    currency: 'USD'
  }
});

Testing Events

1. Meta Pixel Helper

Chrome extension shows events firing in real-time.

2. Events Manager Test Events

  1. Go to Events Manager → Test Events
  2. Enter your site URL
  3. Perform actions
  4. Verify events appear

3. Browser Console

// Log all Meta Pixel events
window.fbq = new Proxy(window.fbq, {
  apply: function(target, thisArg, args) {
    console.log('Meta Pixel:', args);
    return target.apply(thisArg, args);
  }
});

Common Issues

Issue Cause Solution
Events not firing fbq not defined Check Meta Pixel installation
Duplicate events Multiple tracking code Use one installation method
Missing parameters Incorrect object structure Verify parameter names match Meta docs
Product ID not tracked SKU not available Fallback to product.id
Purchase not tracked Order ID not in URL Ensure Wix passes orderId to thank you page

Best Practices

  1. Use standard events when possible (better for optimization)
  2. Include value and currency for conversion events
  3. Send content_ids for all ecommerce events
  4. Implement deduplication when using CAPI + browser pixel
  5. Test thoroughly before launching campaigns
  6. Monitor Events Manager for errors
  7. Hash all PII before sending to Meta
  8. Respect user privacy with consent management

Event Parameter Reference

Common parameters for standard events:

{
  content_ids: ['SKU123'], // Array of product IDs
  content_name: 'Product Name',
  content_type: 'product', // or 'product_group'
  content_category: 'Shoes',
  contents: [{ id: 'SKU123', quantity: 2, item_price: 29.99 }],
  value: 59.98,
  currency: 'USD',
  num_items: 2,
  // Additional
  predicted_ltv: 100.00,
  status: 'completed'
}

Next Steps

Additional Resources

// SYS.FOOTER