JavaScript Events
The Pixel Manager exposes a JavaScript event API on top of jQuery's event system. It works in two directions:
- Listen to
pmw:event:*events to react to everything the Pixel Manager tracks, with the fully processed payload. - Trigger a
pmw:*event to tell the Pixel Manager that something happened that it could not detect on its own.
Both are supported entry points for your own code and for third party plugins.
The pmw:* trigger events have existed for a long time. The pmw:event:* listener API was introduced in version 1.52.1.
Which direction do you need?
| You want to | Use | Example |
|---|---|---|
| Send data to another system whenever the Pixel Manager tracks something | Listen to pmw:event:* | Push every purchase into your own analytics endpoint |
| Add a pixel or a conversion the Pixel Manager does not cover | Listen to pmw:event:* | Fire a partner network tag on purchase |
| Make the Pixel Manager track an interaction it cannot see | Trigger pmw:* | A headless or custom-built add-to-cart button |
| Adjust the data before it reaches a platform | Neither, use Event Filters | Rewrite the product ID sent to Meta |
If you only want to change data that the Pixel Manager already sends, use Event Filters instead. Filters run inside the pipeline and modify the payload. The events on this page run around it.
Listening to events
Listen to pmw:event:<event-name>. The event name is the tracking event with underscores replaced by hyphens, so add_to_cart becomes pmw:event:add-to-cart.
jQuery(document).on("pmw:event:purchase", function (event, payload) {
console.log(payload.event); // "purchase"
console.log(payload.event_data); // the order, product, cart, etc.
console.log(payload.context); // url, referrer, page_type, consent, ...
console.log(payload.pixels); // the data adapted per pixel
console.log(payload.firing); // which pixels fired browser-side and server-side
});
These events fire after the Pixel Manager has processed the event, applied all filters and decided which pixels fire. That makes them the right place to read final, authoritative data.
Available events
Every event the Pixel Manager processes is dispatched:
| Event | Fires when |
|---|---|
pmw:event:page-view | A page is viewed |
pmw:event:view-item | A product is viewed |
pmw:event:view-item-list | A product list becomes visible |
pmw:event:view-category | A product category page is viewed |
pmw:event:select-item | A product in a list is clicked |
pmw:event:search | A search results page is viewed |
pmw:event:add-to-cart | A product is added to the cart |
pmw:event:remove-from-cart | A product is removed from the cart |
pmw:event:view-cart | The cart is viewed |
pmw:event:add-to-wishlist | A product is added to a wishlist |
pmw:event:begin-checkout | The checkout starts |
pmw:event:add-shipping-info | A shipping method is selected |
pmw:event:add-payment-info | A payment method is selected |
pmw:event:place-order | The order button is clicked |
pmw:event:purchase | The purchase confirmation page is reached |
pmw:event:login | A customer logs in |
pmw:event:account-created | A customer account is created |
The payload
| Key | Contents |
|---|---|
event | The event name in its canonical form, e.g. add_to_cart |
event_data | The core data of the event: product, order, and so on. Empty for events that carry no data of their own |
context | timestamp, url, referrer, user_agent, page_type, user_id and the full consent state |
pixels | The event data adapted to each active pixel's own format |
firing | Per pixel, whether it fired in the browser and whether it fired server-side |
Respect consent
The payload is dispatched regardless of the visitor's consent state, so that your code can make its own decision. payload.context.consent tells you what the visitor allowed:
jQuery(document).on("pmw:event:purchase", function (event, payload) {
// Only act if the visitor accepted marketing cookies
if (!payload.context.consent.categories.marketing) return;
// Your code here
});
If your code sets cookies or sends personal data to a third party, you are responsible for honoring consent yourself. The Pixel Manager only applies consent to its own pixels.
Triggering events
Trigger pmw:<event-name> on document when the Pixel Manager cannot detect an interaction on its own. This is the same entry point the Pixel Manager's own listeners use, so the event goes through the entire pipeline: filters, all active pixels, server-side tracking and consent handling included.
jQuery(document).trigger("pmw:add-to-cart", product);
Available events
| Event | Argument | Notes |
|---|---|---|
pmw:add-to-cart | product object | See Building a product object |
pmw:remove-from-cart | product object | |
pmw:view-item | product object, optional | |
pmw:view-item-list | product object, optional | |
pmw:view-category | product object, optional | |
pmw:select-item | product object | |
pmw:add-to-wishlist | product object | |
pmw:search | none | Reads the search term from the page |
pmw:view-cart | none | |
pmw:begin-checkout | none | Deduplicated against the Pixel Manager's own checkout triggers |
pmw:add-shipping-info | {shippingTier: {slug, text}} | |
pmw:add-payment-info | {paymentType: {slug, text}} | |
pmw:place-order | none | |
pmw:purchase | none | Reads the order from the data layer |
pmw:login | none | |
pmw:account-created | none |
Do not trigger pmw:purchase to report an order the Pixel Manager did not already know about. It reads the order from pmwDataLayer.order, which is written by the plugin on the purchase confirmation page, and it does not bypass the order duplication prevention. Reporting purchases from your own code is not a supported path.
Building a product object
The product argument is not free-form. Build it with the Pixel Manager's own helper so it carries every field the pixels expect:
let product = pmw.getProductDetailsFormattedForEvent(productId, quantity);
If the product is not in the data layer yet, because it was never rendered on the page, fetch it from the server first:
if (!pmwDataLayer.products[productId]) {
await pmw.getProductsFromBackend([productId]);
}
Complete example: a custom add-to-cart button
This is how the Pixel Manager's own Doofinder integration works. It listens to the search plugin's event and hands the product to the Pixel Manager:
document.addEventListener("doofinder.cart.add", async function (event) {
const {item_id, amount} = event.detail;
// Make sure the product is in the data layer
if (!pmwDataLayer.products[item_id]) {
await pmw.getProductsFromBackend([item_id]);
}
if (!pmwDataLayer.products[item_id]) return;
const product = pmw.getProductDetailsFormattedForEvent(item_id, amount);
if (!product) return;
jQuery(document).trigger("pmw:add-to-cart", product);
});
Trigger the event only for the tracking. If the product was already added to the WooCommerce cart, either by your own code or on the server, do not call pmw.addProductToCart() as well. That would add it a second time in the Pixel Manager's own cart state.
Load order
Your listeners have to be attached before the Pixel Manager fires its events, and your code must not run before pmw exists. Both are solved by the command queue:
window._pmwq = window._pmwq || [];
window._pmwq.push(function () {
jQuery(document).on("pmw:event:add-to-cart", function (event, payload) {
// Your code here
});
});
This works no matter when the Pixel Manager loads, which matters on shops that delay or lazy load JavaScript.
Lifecycle events
Besides the tracking events, the Pixel Manager dispatches a few events about its own state. They fire in this order:
| Event | Fires when |
|---|---|
pmw:load-pixels | All active pixels have been loaded and are about to initialize |
pmwLoad | The Pixel Manager finished loading and pmw is available |
pmw:ready | The page has finished loading and the Pixel Manager is fully operational |
These three are native browser events dispatched on document, so they work with addEventListener as well as with jQuery's .on():
document.addEventListener("pmwLoad", function () {
// pmw is available from here on
});
For your own code, prefer the command queue over pmwLoad. The queue also runs your function when the Pixel Manager loaded before your script did, which pmwLoad does not, because the event has already fired by then.
Debugging
Turn on the console logger by loading any page with ?pmwloggeron. It prints a line for every event that enters and leaves the pipeline, which tells you immediately whether your triggered event arrived:
Pixel Manager: pmw:add-to-cart event fired
Pixel Manager: Processing event: add_to_cart
Pixel Manager: Public event dispatched: pmw:event:add-to-cart
Switch it off again with ?pmwloggeroff.
Stability
The event names and the payload structure on this page are a public API and we keep them stable. Two notes:
- Internal
pmw:pixel:*andpmw:s2s:*events also exist. They are the plumbing between the pipeline and the individual pixels. Do not build on them, they change with the pixel implementations. - New keys may be added to the payload. Read the keys you need instead of assuming a fixed shape.