The exact ga4 event schema for subscription saas that tracks upgrades, churn triggers and ltv

The exact ga4 event schema for subscription saas that tracks upgrades, churn triggers and ltv

I’ve spent a lot of my time helping SaaS teams get analytics out of the messy parts of subscription businesses — upgrades, downgrades, failed payments and the small events that predict churn. GA4 gives us a flexible event model that’s perfect for subscription SaaS, but that flexibility is also a problem: without a clear schema you end up with fragmented events, duplicate revenue, and LTV numbers you don’t trust.

Why a strict event schema matters for subscription SaaS

In subscription businesses you’re not just tracking one-off purchases. You need to track recurring revenue, billing cycles, trials, plan changes, refunds, and the events that often precede churn (like payment failures or downgrades). A consistent GA4 schema helps in three ways:

  • Accurate revenue and LTV calculations — avoid double-counting and make sure renewals are attributed correctly.
  • Reliable churn triggers — surface the events that matter so you can automate retention workflows.
  • Clean downstream analysis — when data lands in BigQuery you can easily join events by subscription_id rather than guess at linking by user or session.
  • High-level event list I standardise for every subscription SaaS

    Here are the events I implement as minimum viable instrumentation for subscription products:

  • subscription_start (first paid conversion)
  • subscription_renew (recurring billing success)
  • subscription_cancel (user-initiated cancel)
  • subscription_expire (subscription lapses at end of paid period)
  • payment_failed (billing failure)
  • subscription_upgrade / subscription_downgrade (plan change)
  • trial_start
  • trial_convert (trial -> paid)
  • purchase (for add-ons or one-off purchases)
  • refund
  • The exact event payload I send to GA4

    Below is the core event schema I use. Consistency in parameter names is the single biggest win — use these exact keys across all events.

    FieldTypeNotes
    event_namestringOne of the canonical names above (e.g. subscription_renew).
    subscription_idstringUnique, immutable ID for the subscription (not the order).
    user_idstringYour internal user ID (for deterministic joins in BigQuery).
    plan_idstringProduct or plan SKU.
    plan_namestringHuman readable plan label.
    billing_cyclestringe.g. monthly, annual.
    billing_period_startdatetime (ISO)Start of the billed period (UTC).
    billing_period_enddatetime (ISO)End of the billed period (UTC).
    amountfloatGross amount charged in the event currency.
    currencystringISO currency code (USD, GBP).
    taxfloatTax component (optional).
    discountfloatDiscount applied (optional).
    transaction_idstringUnique charge/order id — use to dedupe revenue in GA4 and BigQuery.
    cancel_reasonstringUser-provided reason for cancellation (if available).
    churn_triggerstringOptional, e.g. payment_failed, user_request, non_renewal.

    Mapping GA4 recommended events / parameters

    Where possible I map to GA4’s ecommerce and subscription semantics so built-in reports and integrations behave better. Example mapping:

  • subscription_start -> event: subscription_start + parameters listed above
  • subscription_renew -> event: subscription_renew (also send ecommerce_purchase if you want it to appear in monetization reports)
  • purchase (add-on) -> use purchase with items[] array for add-on SKU details
  • refund -> event: refund with transaction_id and refund_amount
  • When sending revenue I always include transaction_id and currency. That lets GA4 dedupe the same transaction if your backend and frontend both send the event.

    How I handle upgrades, downgrades and proration

    Plan changes are a common source of confusion. I surface both the change event and the financial effect:

  • Send subscription_upgrade or subscription_downgrade with parameters old_plan_id, new_plan_id, proration_amount, proration_currency.
  • If a prorated charge occurs, also send a purchase or subscription_renew event with transaction_id and amount so revenue is tracked.
  • By including proration_amount and referencing subscription_id + transaction_id you can clearly attribute any one-off charges to a plan change in BigQuery.

    Churn triggers — the events you should prioritise

    Not all cancellations happen cold — many are preceded by signals you can act on. Track these as discrete events:

  • payment_failed — include failure_code and retry_attempt.
  • grace_period_started — when you allow a customer to continue while retrying payments.
  • support_contacted_for_billing — if your support system creates tickets.
  • downgrade_request — separate from an immediate downgrade event.
  • cancellation_page_viewed — useful to measure self-serve churn intent.
  • Combine these into an audience like “high churn risk” (payment_failed OR (grace_period_started AND cancellation_page_viewed within 7 days)). That audience can feed retargeting and automated emails.

    Lifetime value (LTV) — where to compute it

    There are two pragmatic options:

  • Compute a rolling LTV user_property in your backend and send it to GA4 as user_property lifetime_value (in your currency). This is simple and fast for ad bidding and audiences.
  • Export to BigQuery and compute historical cohort LTVs there for strategic analysis. Use subscription_id and transaction_id to sum revenue per subscription across the life of the customer.
  • Example BigQuery snippet I use (simplified):

    SQL
    SELECT user_id, SUM(amount) AS total_revenue, COUNT(DISTINCT subscription_id) AS subscriptions FROM analytics.events WHERE event_name IN ('subscription_start','subscription_renew','purchase') GROUP BY user_id

    Dedupe rules and common pitfalls

    Two common issues wreck LTV and revenue numbers: duplicate sends and mis-attributed renewals. My rules:

  • Always include transaction_id for any event that represents money. Use it in GA4 to dedupe and in BigQuery for joins.
  • Choose one source of truth for subscription lifecycle events (backend preferred). If you must send from the client, reconcile server-side and backfill to BigQuery.
  • Keep subscription_id immutable; if a migration creates a new ID, map the old -> new in user_properties.
  • Implementation tips

    Some practical advice from rolling this out across products:

  • Implement server-side event forwarding (Cloud Functions, server endpoint or GTM Server) for critical billing events — it’s more reliable than client-side only events.
  • Use DebugView and Realtime reports during rollout to confirm event names and parameters match your schema exactly.
  • Install GA4 BigQuery export early — you’ll want raw events for verification and retroactive fixes.
  • Keep a single instrumentation spec (JSON or Confluence page) and version it. Share it with product, billing and engineering.
  • Using audiences and conversions

    I convert these events to GA4 conversions where they map to business outcomes:

  • subscription_start and trial_convert as primary conversions.
  • payment_failed and subscription_cancel as negative conversion signals for retargeting (not as GA4 “conversion” which would inflate conversion counts).
  • Audiences I build from this schema include:

  • Active subscribers by plan_id and billing_cycle.
  • Trial-to-paid converters in last 30 days.
  • High churn risk (payment_failed OR downgrade_request within 14 days).
  • Validation checklist before you go live

    Don’t deploy blind. My checklist:

  • Events implemented and visible in DebugView with correct parameter names.
  • Transaction_id present for all revenue events.
  • subscription_id present for all lifecycle events.
  • Server-side duplicates tested and deduped.
  • BigQuery export shows events joined correctly by subscription_id and user_id.
  • Get the schema right once and you’ll get reliable LTV, accurate monetization reporting and early warning on churn. If you want, I can share a downloadable JSON schema you can drop into your dev docs or GTM templates — I’ve built a couple of reusable specs that save teams days of rework.


    You should also check the following news:

    Social Media

    How to build a two-week testing ladder for creative and audience that proves which variant to scale on facebook and instagram

    05/05/2026

    I’m going to walk you through a practical, two-week testing ladder for creative and audience on Facebook and Instagram that I use with clients when...

    Read more...
    How to build a two-week testing ladder for creative and audience that proves which variant to scale on facebook and instagram