MetaTrac self-updates
MetaTrac: WooCommerce -> Meta Pixel + Conversions API tracking plugin
by LifeX Marketing · github.com/lifexmarketing/metatrac · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/lifexmarketing/metatrac/archive/refs/heads/main.zipShips its own WordPress updater (Plugin Update Checker), so new versions show up under Dashboard → Updates.
A WordPress/WooCommerce plugin that tracks core ecommerce and lead-gen events
and sends them to Meta through both the browser Pixel and the server-side
Conversions API (CAPI), so tracking survives ad blockers and iOS ATT opt-outs.
Built as a successor to the internal zooraz (Cloudflare Zaraz) plugin, but
talks to Meta directly instead of going through a dataLayer/Zaraz intermediary.
Installed on multiple client sites and updated centrally from this repo via the bundled Plugin Update Checker.
Requirements
- A Meta Pixel ID and a Conversions API access token (Events Manager > Data Sources > your Pixel > Settings > Conversions API > Generate access token).
- WooCommerce active, only if you want the ecommerce events (
ViewContent,AddToCart,InitiateCheckout,Purchase);PageView,Contact,FindLocation, andLeadall work without it. On the settings screen, the ecommerce checkboxes are grayed out while WooCommerce is inactive. - Gravity Forms active, only if you want the
Leadevent; MetaTrac still works fully without it,Leadjust never fires.
Setup on a site
- Install the plugin (see "Installing / updating" below).
- Go to Settings > MetaTrac (requires the
manage_optionscapability). - Enter the Meta Pixel ID and Conversions API Access Token.
- Check which events to track:
ViewContent,AddToCart,InitiateCheckout,Purchase,Contact,FindLocation,Lead. - Optionally, under Page Events, assign any of Meta's standard events to any published page, to fire that event on every load of that page; see "Page Events" below.
- Optionally turn on Debug Mode while verifying a new install (see "Debug mode" below), and turn it back off once confirmed.
- Optionally paste a Test Event Code from Events Manager > Test Events while verifying CAPI delivery, then remove it.
How events are tracked
Every event fires twice, sharing the same event_id so Meta deduplicates
the browser and server copies:
- Browser (Pixel):
fbq('track', ...), queued during page render and flushed in the footer (or, for ajax add-to-cart, pushed via a WooCommerce fragment, see below). - Server (CAPI): a
wp_remote_post()tograph.facebook.com, includingfbp/fbccookies, client IP/user agent, and, when available, a hashed email/phone for match quality.
Page-cache safety: ViewContent, InitiateCheckout, and Page Events are
queued via Metatrac_Pixel::queue_deferred_event() rather than
fire_event(), since they fire from an ordinary page render that a caching
plugin might serve unchanged to many different visitors. fire_event()
mints the event_id and sends the CAPI call at render time, which is only
safe when that specific render is guaranteed to run fresh per visitor (an
ajax response, or a page with a naturally unique URL like an order-received
page): baking a real event_id into cached HTML would mean every visitor
served from that cache entry fires a Pixel event Meta dedupes away against
the single CAPI call sent when the cache was generated, undercounting real
traffic for as long as the page stays cached. Deferred events instead mint
their event_id in the browser on every real page load (metatracFireEvent()
in assets/js/metatrac-frontend.js) and report it to a dedicated
admin-ajax.php endpoint (metatrac_deferred_event) so the CAPI call runs
fresh every time too, the same approach Contact and FindLocation already
use below, just applied to page-load events instead of click events.
AddToCart and Purchase still use fire_event() directly: the ajax
add-to-cart response is never page-cached, and an order-received URL is
unique per order.
Every one of these admin-ajax.php endpoints (metatrac_deferred_event,
metatrac_contact, and metatrac_find_location) is itself gated by a WP
nonce that's baked into the same cached page render as the event it's
authorizing. A plain wp_create_nonce() is normally only valid for
~12-24 hours, which a page cache can easily outlive (some of the cache
entries that first surfaced the event_id bug above were 43-51 hours old),
so each of the three trackers extends its own nonce's lifetime to a week via
the nonce_life filter (extend_nonce_life() in
Metatrac_Contact_Tracker/Metatrac_Find_Location_Tracker/Metatrac_Pixel).
That comfortably covers realistic cache TTLs without leaving the nonce valid
indefinitely.
Known limitation: a cache entry that somehow outlives a week without
being regenerated or purged would still cause that specific event's CAPI
call to silently fail its nonce check (the Pixel call is unaffected, since
it doesn't depend on the nonce). Turning on Debug Mode surfaces this as a
nonce_check_failed line in the debug log; previously it failed with no
trace at all.
| Event | Fires on |
|---|---|
ViewContent |
Single product page view |
AddToCart |
woocommerce_add_to_cart (ajax or classic form submit) |
InitiateCheckout |
Checkout page load, if the cart isn't empty; deduped per cart contents so refreshing/revisiting an unchanged cart doesn't refire it |
Purchase |
Order-received ("thank you") page, once per order |
Contact |
First click/tap on a tel:/sms: link and/or a mailto: link anywhere on the site (independently toggled), once per browser session |
FindLocation |
First click/tap on a link to Google Maps anywhere on the site (a "Get Directions" link, an embedded map's "View larger map" link, a goo.gl/maps/maps.app.goo.gl short link, etc.), once per browser session |
Lead |
A Gravity Forms submission (gform_after_submission), for the forms selected in Lead's settings (all active forms by default) |
AddToCart and ajax carts
WooCommerce's default ajax add-to-cart doesn't reload the page, so there's no page for the browser Pixel call to run on. MetaTrac handles this the way GTM/analytics plugins typically do: it injects a `