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:
Client-Side Hashing (Not Recommended)
// 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
});
}
}
});
Server-Side Advanced Matching (Recommended)
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
- Go to Events Manager → Test Events
- Enter your site URL
- Perform actions
- 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
- Use standard events when possible (better for optimization)
- Include value and currency for conversion events
- Send content_ids for all ecommerce events
- Implement deduplication when using CAPI + browser pixel
- Test thoroughly before launching campaigns
- Monitor Events Manager for errors
- Hash all PII before sending to Meta
- 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'
}