Loading tutorials…
Loading tutorials…
Firing GA4 through GTM is the foundation of every modern analytics stack. Done right, it's one tag and a clean event map. Done wrong, you double-count every event and pollute six months of reports. This is the right way.
Who this is forSite owners with GTM installed who want to manage GA4 through it (not through gtag.js directly). If you're firing GA4 via both gtag.js AND GTM, you're double-counting — fix this before reading further.
What you'll need
Step 1
If GA4 was previously installed via the Global Site Tag (gtag.js) directly in your site code, remove it. Otherwise GTM and gtag.js fire GA4 twice.
Open your site source (View Source on any page).
Search for 'gtag(' and 'G-XXXXX' (your GA4 ID). If you see either OUTSIDE of the GTM container, that's a direct gtag.js install.
Remove the direct install. If it was added via a plugin (like Google Site Kit), deactivate the GA4 portion of that plugin or remove the plugin entirely.
Verify the next page load shows only ONE gtag firing — and that one comes from GTM. View source: there should be no inline gtag('config', 'G-XXXXX') outside of GTM.
Step 2
The Google Tag is the 2026 replacement for the deprecated GA4 Configuration Tag. It fires gtag.js with your Measurement ID and powers all downstream GA4 events.
GTM → Tags → New → Tag Configuration → Choose Tag Type → Google Tag.
Tag ID: paste your GA4 Measurement ID (looks like G-XXXXXXXXXX, found in GA4 → Admin → Data Streams → Web → Measurement ID).
Under Configuration Settings, leave default unless you need to override (most stacks don't on day 1).
Trigger: All Pages (this is the default 'Initialization - All Pages' trigger you want for GA4 base).
Tag name: "GA4 — Base Config." Save.
Don't add multiple Google Tags for the same property. One is enough — it covers all pages.
Step 3
GA4 captures pageviews automatically through the Google Tag. For everything else (form submits, button clicks, purchases), add a dedicated GA4 Event tag.
Tags → New → Tag Configuration → Google Analytics: GA4 Event.
Measurement ID: paste the same G-XXXXX from step 2 (or use a constant variable {{GA4 Measurement ID}} if you set one up).
Event Name: a snake_case string GA4 will record. Use Google's recommended event names where possible (e.g., "generate_lead," "purchase," "view_item") and custom names only when needed.
Event Parameters: add the key-value pairs you want sent with the event. Example: 'form_id' → {{Form ID}}, 'page_path' → {{Page Path}}. These show up in GA4 → Reports → Realtime → User Property dropdown.
Trigger: your custom trigger (next step).
Tag name: "GA4 — Form Submit" (or whatever the event is). Save.
Step 4
Triggers tell GTM when to fire a tag. For a form submit event, use the Form Submission trigger with a Form ID condition.
Triggers → New → Trigger Configuration → Choose Trigger Type → Form Submission.
Enable "Wait for Tags" and "Check Validation" if your form does client-side validation (prevents firing on invalid submits).
Choose "Some Forms" — this is the conditional firing toggle.
Condition: Form ID equals "contact-form-7" (or whatever the form's ID attribute is on your site). Use DevTools → inspect the form → look for the id attribute.
Trigger name: "Form Submit — Contact Form." Save.
Attach this trigger to the GA4 Event tag from step 3.
Step 5
For events that fire via dataLayer.push() (e.g., purchase, add_to_cart from GTM4WP or Shopify Custom Pixels), use the Custom Event trigger type.
Triggers → New → Custom Event.
Event Name: the exact string used in dataLayer.push({event: "purchase", ...}). For Enhanced Ecommerce v2, this is often "purchase," "view_item," "add_to_cart."
Trigger name: 'GA4 — Purchase DL Event.' Save.
In the corresponding GA4 Event tag, set Event Name to 'purchase' and add Event Parameters that pull from the dataLayer: 'transaction_id' → {{DLV - ecommerce.transaction_id}}, 'value' → {{DLV - ecommerce.value}}, 'currency' → {{DLV - ecommerce.currency}}.
The DLV variables ('Data Layer Variable') are set up in Variables → User-Defined → New → Data Layer Variable. Each pulls a specific path from window.dataLayer.
Step 6
GA4 has a built-in DebugView that shows real-time events from your session. Use it alongside Tag Assistant to confirm every event fires correctly.
In GTM, click Preview (top-right). This opens Tag Assistant attached to your container.
In a separate tab, open GA4 → Configure → DebugView.
Navigate your site through the event flow (e.g., submit a contact form, complete a test purchase).
In Tag Assistant, watch the Tags column: your "GA4 — Form Submit" tag should fire on the corresponding trigger.
In GA4 DebugView, the event should appear within 5-30 seconds with all the parameters you configured.
If anything is wrong (event not firing, wrong parameter values), fix it in GTM Preview mode — the container reloads automatically.
Step 7
When DebugView shows clean events, publish. Set a meaningful version name so you can roll back if needed.
GTM → Submit (top-right).
Version name: "v2 — GA4 base + form submit + purchase." Description: list which tags and triggers were added.
Click Publish. The container goes live within 60 seconds.
Validate one more time on the live site (not Preview mode) — DebugView still shows events; Realtime in GA4 shows events from real visitors.
Schedule a 7-day check: are events firing in GA4 reports at expected volumes? If volume looks 2x normal, you have a double-fire issue and need to revisit step 1.
Common mistakes
Running GA4 in both gtag.js AND GTM
What goes wrong: Every event fires twice. Pageviews, sessions, conversions all inflate 2x. Bid strategies trained on this data over-bid by 50-100% because they think ROAS is twice reality. Months of wasted ad spend.
How to avoid: Audit page source for any gtag('config', 'G-XXXXX') outside of GTM. Remove all of them. GTM should be the only place GA4 fires.
Using the deprecated GA4 Configuration Tag
What goes wrong: The GA4 Configuration Tag was deprecated in 2024 in favor of Google Tag (gtag.js). Old tutorials still reference it. Tags using it still work but won't get future features. Eventually it sunsets.
How to avoid: Use Tag Type → Google Tag (gtag.js) for base config. The old GA4 Configuration Tag is hidden but still exists in some templates — don't use it for new installs.
Firing every custom event with the same Event Name
What goes wrong: All your custom events show up as one giant blob in GA4. Reports can't distinguish between form submits and add-to-cart actions. Funnel analysis is impossible.
How to avoid: Use distinct Event Names per action. GA4 has reserved names (purchase, view_item, generate_lead) — use those when applicable. Use custom snake_case names (e.g., 'newsletter_signup,' 'demo_requested') for the rest.
Forgetting to mark events as 'Key Events' in GA4
What goes wrong: Events fire correctly but Google Ads can't import them as conversions. You wonder why 'Import from GA4' shows zero events. Wasted hours debugging GTM when the issue is in GA4.
How to avoid: GA4 → Admin → Events → toggle "Mark as Key Event" for each event you want to import into Google Ads or use as a conversion.
Not adding event parameters
What goes wrong: Events fire but carry no context. You see 'form_submit' 47 times but can't tell which form was submitted. Optimization is impossible.
How to avoid: Always pass relevant parameters: form_id, page_path, button_text, value (for revenue events). Set them up in Variables → User-Defined → Data Layer Variable, then pass to the GA4 Event tag.
Publishing without testing in DebugView
What goes wrong: You publish a tag that fires on every page click (instead of specific buttons). GA4 receives 50,000 events on day one. Your event quota is consumed and reports are noise.
How to avoid: Always test in Preview mode + DebugView before clicking Publish. If you see unexpected fires, fix the trigger condition before going live.
Recap
Done — what's next
How to fire Meta Pixel through Google Tag Manager (custom HTML approach)
Read the next tutorial
Hand it off
GA4 + GTM is the foundation of every downstream platform: Google Ads, Meta, server-side, BigQuery. Getting it right once means months of clean data. A GTM specialist will configure the base, set up your top 5-10 events, and validate end-to-end. Typically $300-500 one-time at $14-16/hr.
See specialist rates
Google deprecated the GA4 Configuration Tag in 2024 and replaced it with the Google Tag (gtag.js). The new tag does the same job — initialize gtag.js with your Measurement ID — but is the only version that gets new features (consent mode v2 deep integration, server-side enhancements). Use Google Tag for all new installs.
One tag per event name is the cleanest. You can fire the same tag from multiple triggers if the parameter values are the same, but the moment you want different parameters per trigger, split into separate tags. Easier to maintain and debug.
Three causes in priority order: (1) the event isn't marked as a Key Event in GA4 Admin — reports filter by Key Events by default; (2) GA4 has a 24-48 hour processing delay for reports (Realtime and DebugView are instant, standard reports lag); (3) your event parameter values are mismatched — for purchase events, GA4 requires transaction_id, value, currency to be present.
Yes, and for stacks at $5K+ monthly ad spend it's usually worth it. Server-side GTM proxies GA4 traffic through your own subdomain, restoring attribution that's lost to iOS ITP and ad blockers. See the server-side GTM tutorial for setup.
No. Track meaningful actions: form submits, signups, purchases, downloads, video plays. Tracking every click pollutes your data and consumes the GA4 event quota (10M/month free tier). Use Enhanced Measurement (Admin → Data Streams → toggle settings) for default events; add custom only for things that matter.
Google Tag Manager
Meta doesn't ship a native GTM tag template, so the install is a Custom HTML tag. Done right, this is cleaner than the official Meta pixel-injection method — done wrong, you double-fire every event and the Events Manager fills with junk.
Google Tag Manager
The default Form Submission trigger handles 70% of forms. The other 30% (AJAX forms, React forms, Webflow forms) need a custom pattern. This walks through both, and which one you need.
Google Tag Manager
If a tag isn't firing — or worse, firing when it shouldn't — Tag Assistant is the only honest source of truth. Most operators use it wrong. This walks through the workflow specialists actually use.
Google Tag Manager
DIY GTM works fine for simple stacks. It starts breaking down when you need GA4 + Meta + TikTok + Google Ads all firing accurately with deduplication. Here's the honest framework for when to hire.