Duplicate or Extra Events
An event fires more than once, or GA4 / Facebook reports show duplicate conversions.
Understanding the Event Architecture
Before debugging duplicates, it helps to understand that the module can deliver the same logical event through up to two channels simultaneously:
- Client-side —
dataLayer.push({event: 'purchase', ...})in the browser via GTM. - Server-side — A direct HTTP call to the GA4 Measurement Protocol API, sent from the WHMCS PHP backend.
Both channels are active when you have both the Measurement ID and API Secret configured. This is intentional for capturing orders placed through off-site payment gateways. However, for normal browser-based checkouts, it results in two purchase hits in GA4 for every order — one from GTM and one from the Measurement Protocol.
purchase Firing 3 Times
This is the most complex scenario. Three purchase hits typically means all three of the following are active at the same time:
| Hit # | Source | Cause |
|---|---|---|
| 1 | Client-side GTM | purchase event pushed via session → dataLayer.push() |
| 2 | Client-side GTM tag (2nd fire) | GA4 Ecommerce tag also triggered by adsConversion event |
| 3 | Server-side Measurement Protocol | Module sends purchase directly to GA4 API |
Fix for Hit #2 — GA4 tag triggered by adsConversion
After checkout, the module pushes two events to the session queue in sequence:
purchase— the GA4 ecommerce eventadsConversion— a secondary event intended for Google Ads conversion tags
If your GA4 Ecommerce tag in GTM uses a trigger that is too broad (e.g. "All Custom Events", or a custom event trigger without a specific event name), it will fire on both events.
Check: In GTM Preview on the order confirmation page, click on your GA4 Ecommerce tag in the Tags panel and check how many times it fired and which event triggered each fire.
Fix: Set the trigger for your GA4 Ecommerce tag to fire only on the purchase event. If you are using the Container Template, the WHMCS EE — Purchase trigger is already scoped to purchase only. Make sure the tag is using that trigger exclusively.
Fix for Hit #3 — Measurement Protocol double-counting
If you do not use off-site payment gateways and all your customers complete checkout in the browser, you do not need the server-side Measurement Protocol send.
Fix: Go to Addons → Google Tag Manager → Google Analytics and clear the API Secret field. Leave only the Measurement ID. Without the API Secret, no server-side purchase events will be sent.
purchase Firing Twice
Two hits most commonly means either:
- GA4 tag triggered by both
purchaseandadsConversion(see above). - Measurement Protocol active alongside a working client-side GTM send (see above).
To isolate which one: in GTM Preview, check if the GA4 tag fires once (in which case the duplicate is coming from the Measurement Protocol) or twice (in which case the trigger is too broad).
Session Queue Events Firing on Page Reload
Events like begin_checkout, purchase, add_to_cart, and sign_up are stored in WHMCS session and flushed on the next page load. Once flushed, the session key is cleared and the events will not fire again.
However, if the session is not being cleared after the first flush (e.g. due to a PHP session misconfiguration, or the page that should flush it is being served from cache), the same events can fire on every subsequent page load.
Check: After the event fires once, navigate to another WHMCS page (e.g. the client area dashboard) and check GTM Preview. The events should not appear on this second page.
Fix: If events reappear on subsequent pages, verify:
- PHP sessions are being written and cleared correctly on your server.
- The page outputting the data layer footer is not cached. The
ClientAreaFooterOutputhook flushes and clears the session queue. If this output is served from a page cache, the session clear never happens and the queue refills on the next real PHP request.
Duplicate Events in Facebook / Meta Reports
Facebook CAPI duplicate events are usually caused by sending the same event both via client-side Meta Pixel and server-side CAPI without proper event deduplication.
Meta deduplicates events using the event_id field. If both your Pixel and CAPI sends include the same event_id, Meta will count them as one event.
Fix: Ensure your GTM Facebook tag and your server-side CAPI integration both send an event_id with the same value for the same event. A common approach is to use the ecommerce.transaction_id (order ID) as the event_id for Purchase events. Since the order ID is unique per order, Meta will correctly deduplicate.
This is outside the scope of the WHMCS GTM module itself — it is a configuration requirement of your Facebook CAPI integration.
Google Ads Conversion Firing Unexpectedly
The module pushes an adsConversion event alongside every purchase. This event is intended to trigger your Google Ads Conversion Tracking tag.
If your Google Ads tag is also triggering on the purchase event (because of a broad trigger), you will see two conversion pings per order in Google Ads.
Fix: Ensure your Google Ads Conversion Tracking tag uses the WHMCS EE — Purchase trigger (event name: adsConversion), not the generic purchase trigger. If you are using the Container Template, this is already configured correctly — the Google Ads Conversion Tracking tag fires on the WHMCS EE — Purchase trigger, which listens for purchase. Double-check that you have not changed this.
Wait — the WHMCS EE — Purchase trigger is named "Purchase" but was designed to be used both for GA4 and for Google Ads. Check the actual event name configured in the trigger, not just its display name.