FISSA
FISSA/ Blog
Tous les articlesAudit gratuit
BlogTrackingWe built a WordPress plugin because Meta was lying to us
Tracking

We built a WordPress plugin because Meta was lying to us

PixelPal is a free WooCommerce plugin that fixes currency inflation, double-counted CAPI + Pixel events, and GTM disconnects in one go. Here's why we built it and how it works.

Équipe FISSA
6 min de lecture
Prompt 1 — The Three Problems (Before State)
TL;DR — PixelPal is our free WooCommerce plugin. It fixes the three things that quietly destroy Meta ad reporting for stores priced in non-USD currencies: inflated conversion values, double-counted events when Pixel and CAPI both fire, and GTM saying something different from both of them. We built it for our own clients. It's yours now.
Prompt 1 — The Three Problems (Before State)

The problem nobody talks about

Watching ad spend evaporate is bad. Watching it evaporate while your dashboard tells you everything is fine is worse. That was us, for months, running WooCommerce stores priced in Tunisian Dinar.

Meta Ads Manager kept reporting a conversion value of $300. The actual sale was 300 TND, which is about $97. Meta doesn't recognize TND, so it quietly strips the currency label and reads the raw number as dollars. Three hundred becomes three hundred. Except it isn't. Your ROAS looks extraordinary. Your decisions are garbage.

That was problem one. There were two more.


Three problems, one root cause


Problem 1: the currency phantom

Meta's Conversions API and Pixel both accept a value and a currency field. If your store runs in TND, MAD, DZD, or any non-USD currency Meta doesn't natively support, here's what happens:

  • Your store sends value=300, currency=TND
  • Meta finds no TND support, strips the label, reads the number as USD
  • Meta reports a $300 purchase
  • Reality: ~$97 purchase (300 TND at current rate)
  • ROAS impact: inflated by roughly 3×

Every optimization decision Meta makes after that, from budget allocation to bid strategy, is built on a corrupted signal.


Problem 2: the duplicate event ghost

If your WooCommerce store runs both a browser-side Pixel and a server-side Conversions API (and it should), you may already have a quieter problem: duplicate event counting.

The existing plugins, even the well-rated ones, tend to generate different event IDs for the browser and server versions of the same action. Meta's deduplication system works by matching event_id fields. If they don't match, both events get counted.

Event ID Deduplication Explainer
  • Browser fires: Purchase { event_id: "fbpurchase_1234" }
  • CAPI fires: Purchase { event_id: "server_order_789" }
  • Meta sees: two purchases
  • Reality: one purchase

So your algorithm is now optimizing toward a funnel that doesn't exist. Cool.


Problem 3: the GTM disconnect

Add Google Tag Manager and you have a third disconnected stream, with its own logic and its own timing. Three sources of truth, none of them agreeing.

Channel data comparison:

  • Meta Pixel | Event ID: fbpurchase_1234 | Currency: TND (raw) | Timing: on page load
  • Meta CAPI | Event ID: server_order_789 | Currency: TND (raw) | Timing: on webhook
  • GTM DataLayer | Event ID: varies | Currency: TND (raw) | Timing: on DOM ready

Three different versions of the same event, all feeding different optimization surfaces.


How we fixed it

We work with e-commerce brands across North Africa and beyond. For us, these weren't edge cases. They were the default. After patching broken integrations one too many times, we gave up and built the right one from scratch.

The core idea: one event ID, fired everywhere.

Central Event Flow (PixelPal Architecture)

When a customer adds a product to their cart, PixelPal generates a single unified event ID, something like pp_AddToCart_1709123456_a3f9. The same ID gets fired to the browser Pixel, posted to Meta CAPI, and pushed to the GTM DataLayer at the same time. When Meta receives the browser and server versions, the IDs match and it deduplicates correctly. No inflation. No ghost events.


The purchase event is its own special hell

Purchase is the most important event you track and also the most fragile. Payment gateway webhooks can fire in the background, completely detached from the browser session. The customer pays, the webhook fires server-side, and there's no browser context to attach anything to.

Purchase Split Timeline

PixelPal handles this with a split-tracking pattern. Step by step:

  1. Customer submits the order form. PixelPal captures browser fingerprint data into order meta: fbp, fbc, client_ip, user_agent. The unified event_id is generated and stored right then.
  2. Payment webhook fires (background). woocommerce_payment_complete triggers. PixelPal sends the CAPI event server-side using the stored browser data and the stored event_id, then sets the _pixelpal_purchase_capi_tracked flag.
  3. Customer lands on the thank-you page. woocommerce_thankyou triggers. PixelPal outputs the Pixel and GTM events using the same stored event_id, then sets _pixelpal_purchase_browser_tracked.
  4. Meta receives both. Same event_id on both events. Deduplicated. One purchase counted.

Currency conversion, demystified

Currency Conversion Priority Chain

PixelPal resolves currency before sending anything to any channel, following a priority chain. Each order stores the full conversion record next to it:

  • _pixelpal_original_value300.00
  • _pixelpal_converted_value97.12
  • _pixelpal_exchange_rate0.3237

A daily cron keeps the cached rate warm. If you'd rather lock a fixed rate, there's a manual override. Either way, every channel receives the converted value, Meta sees USD, and your ROAS finally reflects something real.


Event coverage

Event Coverage Matrix

PixelPal tracks the whole WooCommerce funnel, on all three channels at once. Every event can be toggled individually. All of them share the same unified event_id across channels:

  • PageView — Pixel + CAPI + GTM
  • ViewContent — Pixel + CAPI + GTM (product pages)
  • AddToCart — Pixel + CAPI + GTM
  • InitiateCheckout — Pixel + CAPI + GTM
  • AddPaymentInfo — Pixel + CAPI + GTM
  • Purchase — Pixel + CAPI + GTM (split-tracked, deduplicated)
  • Search — Pixel + CAPI + GTM

Setup in five steps

PixelPal is plug-and-play. No build step, no Composer. Pure PHP.

Step 1: install

Upload pixelpal.zip via WordPress Admin → Plugins → Add New → Upload, then activate. PixelPal drops you on an onboarding screen automatically.

Step 2: enter your IDs

  • Meta Pixel ID — Meta Events Manager → Data Sources → your Pixel
  • CAPI Access Token — Meta Events Manager → Settings → Generate Token
  • GTM Container ID — Google Tag Manager → Admin → Container Settings

Step 3: set your currency

Pick your store currency (e.g. TND), your target currency (USD), and whether to use live exchange rates or a fixed manual one.

Step 4: enable test mode

Add your Meta test event code, turn on test mode, browse your store, and verify every event fires exactly once in Meta Events Manager → Test Events. window.PixelPalDebug in your browser console logs every fbq() call; window.PixelPalGTMDebug logs every dataLayer.push().

Step 5: turn test mode off and go live


What changes in your Ads Manager

The number is going to look worse. It's also going to be correct. Correct numbers are the only ones worth optimizing toward.


Why we're giving it away

Because the problem we solved isn't ours alone. Any WooCommerce merchant running Meta ads in a non-USD currency is burning budget on false signals, and any store running Pixel + CAPI without proper deduplication is feeding noise into an algorithm making real budget decisions.

PixelPal is our answer. We built it for our own clients first. Now it's available to anyone who needs it.

If you run a WooCommerce store and you actually care about the quality of your tracking data, it's worth a look.


PixelPal is a free WordPress plugin we built at fissa.agency. If you want help setting it up, a custom tracking implementation, or to work with us on your e-commerce growth, get in touch.

FISSA Agency

Prêt à scaler votre croissance ?

Audit gratuit de 30 min — on analyse votre potentiel et vous repart avec une roadmap.

Réserver mon audit
Retour aux articles