DEV Community

Ishant Sharma
Ishant Sharma

Posted on

Thanx Loyalty Tracking Breaks the Standard sign_up Pattern. Here's the Fix published

`

If your GA4 sign_up count for Thanx loyalty never matches the Thanx dashboard, the code probably isn't the problem. The firing point is.

Most loyalty tracking is simple: guest clicks "join," you fire sign_up, done. Thanx breaks that because it's built on card tokenization. A guest links a card and purchases get tracked automatically, no app, no scan. Enrollment completes at payment, not on a button, and sometimes there's no sign-up button in the flow at all. Fire sign_up on a click and you'll count intentions, not enrollments.

The fix: fire enrollment on the transaction callback, gated to first purchase

window.dataLayer = window.dataLayer || [];

// Call this on the TRANSACTION-COMPLETE callback, never a button click.
// isFirstPurchase prevents double-counting auto-enrolled guests.
function trackThanxSignup(memberId, isFirstPurchase) {
  if (!isFirstPurchase) return;
  window.dataLayer.push({
    event: 'thanx_signup',
    loyalty_method: 'card_linked',
    loyalty_program: 'Thanx',
    loyalty_id: memberId // non-PII Thanx member ID, never phone/email/card
  });
}

// Set once on sign-in so GA4 can attribute every purchase to the member.
function setThanxMember(memberId, tier) {
  window.dataLayer.push({
    event: 'set_loyalty_user',
    loyalty_id: memberId, // also set as GA4 user_id
    loyalty_member: true,
    loyalty_program: 'Thanx',
    loyalty_tier: tier
  });
}

Map the rest of the Thanx events to GA4 recommended events: login for sign-ins, earn_virtual_currency for reward unlocks, spend_virtual_currency for redemptions. You get native GA4 reporting instead of custom-event overhead.

The collision that actually breaks dashboards

If you're already tracking orders through Olo, Toast, or another ordering platform, that platform fires a complete GA4 ecommerce sequence including purchase. Bolt loyalty on top without care and you'll double-count revenue. The fix: never fire a second purchase event for loyalty. Attach user_id and a loyalty_member property to the order your ordering platform already tracks instead of sending your own. Keep sendEcommerceData set to false on every loyalty tag, and use the same GA4 Measurement ID across both systems or member lifetime value can't be joined.

Validate with GA4 DebugView: complete one real order as a logged-in member and you should see exactly one purchase, one set of loyalty events, and a populated user_id. Two purchases means a duplicate config somewhere.

Why this matters

Card-tokenized purchases and in-store redemptions happen without a browser open, so some of this has to move server-side via the Measurement Protocol. And without user_id set correctly, you can't prove members actually spend more than non-members, which is the entire reason to run the platform.

I wrote up the full implementation, including the server-side handling, the five Olo/Thanx collision points, and a BigQuery query for true member LTV across a guest's full history, here: Thanx Loyalty Tracking: The Complete GTM and GA4 Guide for Restaurants →

`

Enter fullscreen mode Exit fullscreen mode

``

Top comments (0)