Server-side purchase tracking signed off against billing: revenue within 2 percent of the ledger for a full month, with every variance named and sized.
About this service
The sign-off condition here is a number: GA4 purchase revenue within 2 percent of the billing system across a full calendar month, transaction IDs matching one to one, and every variance line explained. Nothing else counts as finished. Most tracking projects end when the tag fires. This one ends when finance agrees with it.
One revenue definition, written down first:
Week one produces a single page stating what a purchase is and what it is worth, signed by whoever owns the P&L. It sounds trivial and it is where the money is lost. Gross or net of VAT. Shipping and fees in or out. For a subscription: first payment, annualised contract value, or recognised monthly. In publishing, whether a discounted introductory offer books at the offer price or the standing rate, and what a trial counts as on day one versus day thirty. In insurance, whether the event is the quote, the bound policy or first-year commission, and what happens during the cooling-off period. Two teams holding two answers to that question is the usual cause of a reporting argument that has been running for a year.
Billing system as the source of truth:
The purchase event is sent server-side from the billing webhook — Stripe, Adyen, Recurly, Zuora, Piano — not from a browser landing on a confirmation page. A confirmation page fires again on reload, fires on the back button, and does not fire at all when the redirect fails after the money moved. The browser event still runs, carrying client_id, session and consent state, and the two are deduplicated on transaction_id so the platform keeps one purchase with full attribution. Refunds, chargebacks and cancelled policies are posted back as adjustments rather than left to inflate the year.
The dataLayer contract:
Everything upstream of purchase — view_item, add_to_cart, begin_checkout, add_payment_info — is specified as a versioned contract your engineering team owns and can test in CI, with the items array typed field by field, currency explicit on every event, and item_id keyed to the identifier the billing system already uses. We hand over the contract and its test suite. We do not want to be the only people who understand the schema.
Reconciliation:
Then the part nobody sells: a month of running both systems and closing the gap. Timezone boundaries, currency conversion timing, tax jurisdiction handling, orders authorised but never captured, consent-denied sessions where the purchase exists and the journey does not. Each variance category is quantified and either fixed or documented as a permanent known difference with a size attached.
What we do not do:
We do not build a second revenue number to sit beside the audited one. Where the two must differ, the difference is named and bounded. We do not count trial starts, quote requests or lead submissions as purchases, whatever the media agency needs for bidding; those are separate conversion actions and belong in a separate conversation. We do not take this on where the checkout is a third-party hosted flow the client cannot instrument and will not replace.
Who this is not for:
Standard Shopify or WooCommerce stores. A well-maintained app does this properly for a fraction of what we charge, and we will tell you which one. This engagement is for checkouts that are bespoke, regulated, subscription-based or split across systems, where the numbers disagree for structural reasons rather than a missing tag.