Skip to content
Home Guides Analytics
Analytics Intermediate

WooCommerce tracking setup: GA4, Google Ads and Meta without plugin chaos

Which plugin combination works for WooCommerce, why the purchase belongs only on the order confirmation page and how a single test order proves that GA4, Google Ads and Meta see the same order exactly once.

Fabian Weiss, founder of FW Delta Fabian Weiss
13 min 3 to 5 hours including the test order
The Problem

Three plugins send the same order to GA4, Google Ads and Meta, each by its own rules and none of the numbers match the shop

The Fix

One sender per destination, the purchase only on the order confirmation page with order number and a single value definition, proven with a real test order

WooCommerceGoogle Tag ManagerGoogle Analytics 4Google AdsMeta Pixel

Three plugins, three senders, three different numbers

A typical WooCommerce shop has collected tracking over the years: Google for WooCommerce for the ads, Facebook for WooCommerce for the pixel, plus a tag manager plugin that an agency set up at some point. Each of these plugins reports the purchase in its own way. One sends the value with shipping, one without. One fires on every visit to the order confirmation, one only on the first. At the end of the month the ad account shows more orders than the shop itself.

This guide brings order to the setup. It answers three questions: which plugin is responsible for which destination, where exactly the purchase is measured and how a single test order proves that everything is correct.


The decision: official plugins, Tag Manager or all-in-one

There are three common ways to connect WooCommerce to GA4, Google Ads and Meta. All three work. Mixed together they do not.

ApproachWhat is behind itFits when
Official pluginsGoogle for WooCommerce (formerly Google Listings & Ads) measures with its own Google tag for Google Ads, according to its FAQ. Google Analytics for WooCommerce sends the GA4 events. Facebook for WooCommerce delivers pixel and Conversions API in oneYou do not want to maintain a Tag Manager and only need the standard events
Google Tag Manager plus data layer pluginGTM4WP writes the order data into the data layer, all tags live in Tag ManagerOne person should be able to see, change and test every tag in one place
All-in-one pluginPixelYourSite and similar plugins send from WordPress to several platformsSmall shop, no agency, no custom events

The short version of the trade-off:

  • Official plugins are the least work, but each plugin decides for itself what “value” means and when the purchase is reported.
  • Tag Manager is the only option where you decide which number goes to which destination. In return someone has to understand the container.
  • All-in-one is convenient until you need something the plugin did not anticipate.

Our recommendation for shops with ad spend: Tag Manager with GTM4WP, because every number can be traced there. For shops without ad spend the official plugins are enough, as long as you keep the following rule.


The rule: one sender per destination

For each destination (GA4, Google Ads, Meta) there is exactly one sender in the shop. As soon as two plugins report the same purchase to the same ad account, you have duplicate orders that can only partly be removed afterwards.

The plugin documentation is clear on this point. Google for WooCommerce states in its FAQ that the plugin measures ad performance with its own built-in Google tag and provides a filter to disable that tracking if you use Tag Manager instead, explicitly to avoid double tracking. Google Analytics for WooCommerce warns that multiple tracking code instances on the same page can cause issues. Facebook for WooCommerce also provides a filter to disable the plugin’s pixel and Conversions API.

This is what a clean split looks like:

DestinationSenderEverything else
GA4Tag Manager (or Google Analytics for WooCommerce)switched off
Google AdsTag Manager (or Google for WooCommerce)switched off
MetaFacebook for WooCommerce (pixel plus Conversions API) or Tag Manager plus your own serverswitched off

One point is often overlooked: you can keep using Google for WooCommerce for the product feed and Merchant Center and still switch off its tracking. Feed and measurement are two separate functions of the same plugin.


The order confirmation is the only place for the purchase

After checkout, WooCommerce appends the order-received endpoint to the checkout URL. The endpoint documentation lists it as “Order received (thanks)”. That is the page where the purchase is measured. Nowhere else.

Why only there:

  • On the checkout page the order does not exist yet or is not paid yet. Reporting the purchase there counts abandoned payments.
  • Payment providers such as PayPal, Klarna or Stripe redirect back to the shop after payment. The WooCommerce Payment Gateway API provides get_return_url( $order ) for this, which is the order confirmation. If a gateway shows its own thank-you page instead or the return is optional, the buyer never arrives on order-received. GTM4WP names this in its list of failure causes as the most common reason for missing purchases.
  • Reloading the order confirmation creates a second purchase without protection. That is why GTM4WP, according to its settings reference, flags orders that have already been measured and by default only measures orders younger than 30 minutes.
  • Custom thank-you pages from checkout plugins or page builders do not trigger the WooCommerce hooks of the order confirmation. GTM4WP has the option “Custom order received (thank-you) page” for this, PixelYourSite requires its own add-on for custom thank-you pages.

In Tag Manager the purchase looks like this in the data layer. GTM4WP creates this push itself once “Track e-commerce” is enabled:

window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
  event: "purchase",
  ecommerce: {
    transaction_id: "10482",
    value: 80.00,
    tax: 15.20,
    shipping: 4.90,
    currency: "EUR",
    items: [
      { item_id: "SKU-2201", item_name: "Example product", price: 80.00, quantity: 1 }
    ]
  }
});

The GA4 tag, the Google Ads conversion tag and an optional Meta tag all hang on the same purchase trigger. One order, one push, three tags. Google’s data layer documentation describes how Tag Manager processes these pushes in order.


Order number, value and currency

Three fields decide whether the shop and the ad account mean the same order.

The order number as transaction ID. GA4 uses the transaction_id to avoid duplicate purchases, according to its event reference. Google Ads recognises the second conversion with the same ID as a duplicate, according to its help page on transaction IDs. The same page warns against hardcoded or repeated values because they lead to significant undercounting of conversions. Use the WooCommerce order number, unchanged, in all three destinations.

Value: net or gross, but the same everywhere. GA4 defines value as the sum of price times quantity for all items and says explicitly: do not include shipping or tax, which are sent separately. Google Ads expects a number with a period as decimal separator plus a currency, according to its help page on transaction-specific values, but does not specify whether tax and shipping are included. Meta requires value and currency for Purchase, according to the pixel reference, again without a rule on tax. That means: the definition is yours to make. Pick one (item value without tax and shipping is the obvious choice because GA4 prescribes it), write it down and configure every plugin to match. GTM4WP has the options “Exclude tax from revenue” and “Exclude shipping from revenue” for this, both off by default.

Currency as ISO code. EUR, not €. In shops with several currencies the currency has to come from the order, not from the shop setting.

FieldGA4Google AdsMeta
Order numbertransaction_idtransaction_idevent_id for matching pixel and server
Valuevalue without tax and shippingvalue, definition is yoursvalue, definition is yours
Currencycurrencycurrencycurrency

On WordPress, the cookie banner and the tracking plugins run side by side and have to talk to each other. There are two layers for that.

WP Consent API. The WP Consent API is a plugin that standardises the communication between the cookie banner and other plugins. It knows five categories: functional, preferences, statistics, statistics-anonymous and marketing. Important, according to its documentation: the plugin itself does not handle consent and does not block anything. It is a framework through which a plugin can ask whether consent exists for a category. Whether your tracking plugin and your cookie banner use this framework is stated in their respective documentation.

Consent Mode for the Google tags. Borlabs Cookie describes two ways in its Consent Mode v2 guide. The first runs through its own services for Google Analytics and Google Ads, where basic Consent Mode is already enabled with the package. The second runs through its Google Tag Manager service for more complex setups. Real Cookie Banner explains in its guide to Tag Manager and Consent Mode that Tag Manager is blocked until consent is given and that consents are passed to Tag Manager as additional consent types, so a tag only fires when the matching type shows “Granted”.

What that means for the purchase: without consent, the browser sends nothing in basic Consent Mode, not even the purchase. GTM4WP names this explicitly as a reason for missing purchases. That is not a bug but the result of the decision your cookie banner enforces. How to connect banner and Consent Mode technically is covered in the guide Connect your cookie banner to Consent Mode v2.


Your own server: three routes for WooCommerce

If some buyers never see the order confirmation or block tracking in the browser, only a report from the server helps. WooCommerce offers three connection points for that.

1. Conversions API in Facebook for WooCommerce. According to the documentation, the Conversions API is integrated out of the box, with no additional setting and the events from pixel and server are deduplicated through a shared event ID. This is the simplest route to Meta and the reason the plugin stays the sender for Meta in the table above, even if everything else lives in Tag Manager.

2. Order webhook or woocommerce_payment_complete. According to the webhook documentation, WooCommerce can send a message to a URL on every new or changed order, signed with a secret key. The delivery logs are under WooCommerce, Status, Logs. The topics for this are called order.created and order.updated. Alternatively you hook into the woocommerce_payment_complete action, which WooCommerce fires once payment is confirmed, according to the Payment Gateway API. A small service receives the order and passes it on with order number, value and currency to GA4, Google Ads or Meta. The setup is described in the server-side tracking guide.

3. Google’s Data Manager API. According to Google, the Data Manager API accepts conversion events with a transaction ID as an additional data source alongside the Google tag and allows later value corrections, such as finalised cart totals. Google names a 14-day trial period for these multi-source conversions before they flow into bidding.

For all three: the server complements the browser, it does not replace it. Deduplication details are in the Meta Conversions API guide.


Verify with a real test order

Test mode, sandbox and preview are not enough. Create a coupon for 100 percent, order a real product with a real payment method and work through the list. The coupon makes sure no money moves while the order still goes through every step a customer goes through.

  1. Before the order: Enable DebugView in GA4. According to Google’s help, this works through Tag Assistant or the debug_mode parameter in the tag. In parallel, open the test events tool for your pixel in Meta Events Manager.
  2. Checkout: Pay with a payment method that redirects externally, not with invoice. Only that tests the return.
  3. Order confirmation: Filter the network requests in the developer tools for collect (GA4), googleadservices (Google Ads) and facebook.com/tr (Meta). Exactly one purchase per destination may leave. Note order number, value and currency from each request.
  4. Reload: Reload the order confirmation. No second purchase may leave.
  5. GA4 DebugView: The purchase appears with transaction_id, value, currency and the items. The value matches your definition from the section above.
  6. Google Ads: Open the conversion action. According to Google’s help, “Unverified” means the tag has never fired. After the test order the status should change within the period Google names. The status overview explains “Active”, “Needs attention”, “Misconfigured” and “Awaiting conversions”.
  7. Meta Events Manager: In the test events tool, the pixel event and the server event appear. According to the deduplication documentation, both are only merged if event_id and event_name match and the second arrives within 48 hours of the first. The tool shows which event was processed and which was deduplicated. If both are processed, Meta counts twice.
  8. Cancellation: Cancel the test order in the shop so it does not stay in the revenue statistics.
  9. The next day: Compare the day’s orders in the shop with GA4 and the ad account. Small gaps from cookie rejection are normal, duplicate order numbers are not.

The five most common WooCommerce failures

FailureHow you recognise itCauseFix
Plugin sends the purchase twiceAd account shows more orders than the shop, often almost exactly twice as manyTwo plugins report to the same destination or one plugin fires again on reloadOne sender per destination, order number as transaction ID, keep the reload protection on
Purchase on checkout instead of order-receivedMore purchases than paid orders, values without order numberTrigger on the checkout URL instead of the order confirmation endpointMove the trigger to the purchase push or the order-received URL
Caching plugin serves a cached thank-you pageAll purchases carry the same order number or the Tag Manager container is missing only on this pageCheckout pages were not excluded from the cacheExclude cart, checkout and my account from the cache, as the WooCommerce documentation requires
Payment gateway returns to a different pagePurchases with PayPal or Klarna are missing, invoice orders are completeReturn in the gateway off or custom thank-you page without WooCommerce hooksEnable automatic return, register the custom thank-you page in the plugin, server route for the rest
Tax and shipping inconsistentGA4 revenue and ad account revenue differ by a fixed percentage or a fixed amountOne plugin sends gross with shipping, the other netFix one definition, configure every plugin to match, recalculate with the test order

Where this fits

WooCommerce tracking is not hard, it is just configured in many places at once. The web tracking service does exactly that: audit the plugin inventory, fix the senders, set up the purchase on the order confirmation with order number and value, test order as acceptance. If some orders never reach the browser, server-side tracking comes on top, not before.

If you first want to know whether your shop is affected at all, the tracking check is enough.

FW Delta sets up the technology. Which consent your cookie banner has to collect and on which legal basis stays with you and your legal advisers. This guide is a technical explanation, not legal advice.

Newsletter

Research for technical decisions

New reports, benchmarks and technical analyses on SaaS economics, AI engineering and owned infrastructure.

Original research Public sources No sales mail

By subscribing you receive new analyses and updates from FW Delta by email. You can withdraw your consent at any time. Further information is available in the privacy policy.