Tutorial · GA4 · 18 min

    GA4 Setup from Scratch — A Pragmatic Walkthrough

    Property, data stream, consent mode, conversions and a sane event taxonomy. Skip the bloat.

    1. Step 01

      Create the property

      In the Admin panel, create a new GA4 property. Pick the reporting time zone that matches your finance close, not your office — it'll save you a quarter-end argument later.

      Currency: set to the currency your revenue is reported in, not the visitor's currency. GA4 will not convert historical data if you change this later.

    2. Step 02

      Add a web data stream

      Enable Enhanced Measurement, then turn off the events you don't actually want. Defaults that are usually noise:

      • scroll — fires on 90% scroll, drowns out real signals.
      • video_progress — only useful if video is core to the experience.
      • file_download — keep if you publish PDFs/whitepapers; off otherwise.
    3. Step 03

      Wire GTM

      Install the GTM container in <head>. Use the official snippet — do not lazy-load it; consent mode depends on it being available early.

      // GTM container snippet — top of <head>
      (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
      new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
      j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
      'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
      })(window,document,'script','dataLayer','GTM-XXXXXXX');

      In GTM, create one GA4 Configuration tag firing on All Pages, then one GA4 Event tag per custom event. Do not enable "Send a page view event" on the Config tag if you're pushing your own page_view from the dataLayer (you'll double-count).

    4. Step 04

      Consent mode v2 (required in EU/UK)

      Set default consent before GTM loads:

      <script>
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('consent', 'default', {
          ad_storage: 'denied',
          ad_user_data: 'denied',
          ad_personalization: 'denied',
          analytics_storage: 'denied',
          wait_for_update: 500
        });
      </script>

      Then call gtag('consent', 'update', {...}) after the user chooses.

    5. Step 05

      Define your event taxonomy

      Pick a verb-noun pattern and stick to it: wallet_funded, p2p_send_completed, merchant_pay_completed. Document it in a spreadsheet shared with engineering.

    6. Step 06

      Set conversions

      Mark only the events that map to revenue or product-qualified leads. For a wallet, that's wallet_funded, p2p_send_completed and merchant_pay_completed — not page_view.

    7. Step 07

      Cross-domain and subdomain

      If you have app.example.com and www.example.com, configure them as one data stream with cross-domain measurement to preserve session continuity.

    8. Step 08

      Validate with DebugView before you ship

      Use the GA Debugger Chrome extension or ?_dbg=1 URL parameter, open Admin → DebugView, and walk every critical flow. If you can't see the event there, it isn't being recorded.