# WeWeb Google Analytics: GA4, GTM, and SPA Event Tracking

- Tool: WeWeb
- Difficulty: Beginner
- Time required: 20-30 min
- Compatibility: WeWeb Free plan and above; Google Tag Manager and GA4 accounts required (both free)
- Last updated: March 2026

## TL;DR

The easiest way to add Google Analytics 4 to WeWeb is through the native Google Tag Manager plugin (Plugins → Extensions → Google Tag Manager, enter your GTM Container ID). GTM then manages GA4 tracking including SPA page views, which require a custom GTM trigger since WeWeb navigation does not fire standard pageview events. Setup takes about 20 minutes.

## Google Analytics 4 Tracking in WeWeb

WeWeb generates Vue.js single-page applications (SPAs). In a SPA, page navigation does not trigger browser full-page reloads — the URL changes via JavaScript's History API but no new HTML document is fetched. This breaks standard Google Analytics page tracking, which relies on detecting page loads. WeWeb solves this with a native Google Tag Manager plugin. GTM is injected once, and you configure it to detect WeWeb's SPA navigation events and fire GA4 page_view events accordingly. This tutorial walks through the GTM plugin setup, GA4 configuration inside GTM, SPA history tracking, custom event pushing from WeWeb workflows, and how to test that everything works before going live.

## Before you start

- A WeWeb project open in the editor (Free plan or above)
- A Google Tag Manager account with a container created (tagmanager.google.com — free)
- A Google Analytics 4 property created in Google Analytics (analytics.google.com — free)
- Your GTM Container ID (format: GTM-XXXXXXX) and GA4 Measurement ID (format: G-XXXXXXXXXX)

## Step-by-step guide

### 1. Install the Google Tag Manager plugin in WeWeb

In the WeWeb editor, click the plug icon in the left sidebar to open the Plugins panel. Under the 'Extensions' section, find 'Google Tag Manager' and click Add. In the plugin configuration dialog, enter your GTM Container ID in the 'Container ID' field — it looks like GTM-XXXXXXX. You can optionally enter separate Container IDs for different environments (Editor, Staging, Production) if you use multiple GTM containers. Click Save. WeWeb will inject the GTM snippet (`<script>` in the head and `<noscript>` in the body) into every page of your application automatically. You do not need to add any code manually to App Settings → Custom Code.

**Expected result:** Google Tag Manager plugin appears in Plugins → Extensions with a green active indicator. Your GTM container ID is visible in the plugin config.

### 2. Connect GA4 to your GTM container

Open Google Tag Manager (tagmanager.google.com) and go to your container. Click 'Tags' in the left sidebar → 'New'. Name the tag 'GA4 Configuration'. Click 'Tag Configuration' → 'Google Tag' (the newer recommended tag type that replaces the old GA4 Configuration tag). Enter your GA4 Measurement ID (G-XXXXXXXXXX). Under 'Triggering', click the '+' button. Select 'Initialization - All Pages' as the trigger — this fires the tag on every page load including SPA navigation when combined with the history change trigger in the next step. Click Save. This tag establishes the GA4 connection and initializes the gtag.js tracker for all subsequent events.

**Expected result:** A GA4 Google Tag appears in your GTM workspace configured with your Measurement ID and the Initialization trigger.

### 3. Configure SPA page view tracking with a History Change trigger

WeWeb navigation changes the browser URL without a full page reload, so the 'All Pages' trigger only fires once when the app first loads. To track every SPA page view, you need a GTM History Change trigger. In GTM, click 'Triggers' → 'New'. Name it 'History Change - SPA Navigation'. Under 'Trigger Type', select 'History Change'. Leave all conditions as default (fire on all history changes). Click Save. Now go back to your GA4 tag → edit it → under 'Triggering' click '+' again and add this History Change trigger alongside the existing Initialization trigger. This means GA4 fires once on first load AND every time the WeWeb app navigates between pages. Click Save. Publish your GTM container by clicking 'Submit' in the top right.

**Expected result:** GTM workspace shows the History Change trigger assigned to the GA4 tag. GA4 now fires on every WeWeb page navigation.

### 4. Push custom events to GTM dataLayer from WeWeb workflows

WeWeb has a native GTM action in workflows: 'GTM - Push dataLayer event'. This action sends custom event data to GTM's dataLayer, which GTM can then use to fire GA4 custom events. Select any element in WeWeb that you want to track — a sign-up button, a video play, a form submit. Open its workflow (Workflows tab). Add a new action, search for 'GTM' and select 'GTM - Push dataLayer event'. Fill in the Event name (use GA4 naming convention: lowercase_with_underscores, e.g. `sign_up_button_click`). Add parameters as key-value pairs: `button_location` mapped to the page name (`wwPage.name`), `user_type` mapped to whether the user is logged in. In GTM, create a corresponding Custom Event trigger on the event name, and a GA4 Event tag that fires on that trigger.

```
// GTM dataLayer push (for reference — WeWeb uses the built-in GTM action)
// This is what the 'GTM - Push dataLayer event' action sends
// Injection point: Workflow → GTM - Push dataLayer event action
// (You configure this through the WeWeb action UI, not raw code)

// What gets pushed to window.dataLayer:
{
  "event": "sign_up_button_click",
  "button_location": "hero_section",
  "page_name": "{{wwPage.name}}",
  "user_logged_in": false
}

// Alternatively, for manual injection in a Custom JavaScript workflow action:
// Injection point: Workflow → Custom JavaScript action
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  event: 'form_submit',
  form_id: 'contact_form',
  form_source: wwPage ? wwPage.name : 'unknown',
  submission_value: formData ? formData.planTier : 'unknown'
});
return { pushed: true };
```

**Expected result:** Custom events from WeWeb workflows appear in GA4 Real-Time reports and DebugView after the GTM trigger and tag are configured.

### 5. Verify tracking with GTM Preview mode and Tag Assistant

Before going live, verify your tracking setup works. In GTM, click 'Preview' in the top right. A new browser tab opens with your WeWeb app URL in a GTM debug overlay. Navigate through your app — you should see each tag fire in the GTM debug panel at the bottom of the screen. Confirm the 'GA4 Configuration - Google Tag' fires on initialization and on each History Change. Click your tracked elements to verify custom events fire. For GA4 verification, open Google Analytics → Configure → DebugView. If you have the Google Tag Assistant extension installed in Chrome, it shows a badge on your site with tag status. You can also check GA4 Real-Time reports within 30 seconds of page visits — look for active users and events. If GA4 is not receiving data, check that your GTM container is published (not just saved) and that WeWeb is also published.

**Expected result:** GTM Preview shows the GA4 tag firing on page load and History Change events. GA4 DebugView shows real-time events.

### 6. Alternative: Add GA4 directly via Custom Code Head injection

If you prefer to skip GTM and add GA4 directly, go to App Settings (gear icon) → Custom Code → Head section. Paste the GA4 global site tag (gtag.js) code block. Replace G-XXXXXXXXXX with your GA4 Measurement ID. For SPA navigation tracking without GTM, add a custom script that listens to history state changes using the History API's popstate event and calls gtag('event', 'page_view', ...) manually. This method works but is harder to maintain than the GTM approach — any time you want to change tracking, you need to edit code and republish WeWeb. GTM is preferred for most use cases because you can change tags in GTM without touching WeWeb.

```
<!-- Injection point: App Settings → Custom Code → Head -->
<!-- Replace G-XXXXXXXXXX with your GA4 Measurement ID -->

<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){ dataLayer.push(arguments); }
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXXXXX', {
    send_page_view: false  // Disable auto pageview — we handle it manually below
  });

  // SPA navigation tracking for WeWeb
  // Fires a page_view event on every URL change
  let lastPath = '';

  function trackPageView() {
    const currentPath = window.location.pathname + window.location.search;
    if (currentPath !== lastPath) {
      lastPath = currentPath;
      gtag('event', 'page_view', {
        page_location: window.location.href,
        page_path: window.location.pathname,
        page_title: document.title
      });
    }
  }

  // Listen for Vue Router history changes
  window.addEventListener('popstate', trackPageView);

  // Also patch pushState for programmatic navigation
  const originalPushState = history.pushState;
  history.pushState = function() {
    originalPushState.apply(this, arguments);
    trackPageView();
  };

  // Track initial page load
  document.addEventListener('DOMContentLoaded', trackPageView);
</script>
```

**Expected result:** GA4 Real-Time reports show page_view events firing for each WeWeb page navigation without using GTM.

### 7. Add cookie consent integration for GDPR compliance

If your app has users in the EU, you need a cookie consent mechanism before loading analytics. WeWeb has a Privacy & Consent settings section (App Settings → Privacy & Consent) where you can configure a basic consent banner. For more robust consent management, use a third-party Consent Management Platform (CMP) like Cookiebot or OneTrust. In GTM, configure 'Consent Mode v2' by adding a default consent state tag that fires before all other tags: set analytics_storage to 'denied' by default, then update to 'granted' when the user accepts. This is required for GA4 to comply with EU ePrivacy regulations. The GTM consent mode approach is more reliable than building consent logic directly in WeWeb workflows.

**Expected result:** Analytics only loads after user consent, and GTM Consent Mode sends consent state signals to GA4 for compliant data collection.

## Complete code example

File: `ga4-spa-tracking.html`

```html
<!-- Injection point: App Settings → Custom Code → Head -->
<!-- Full GA4 SPA tracking implementation for WeWeb (alternative to GTM plugin) -->
<!-- Replace both instances of G-XXXXXXXXXX with your GA4 Measurement ID -->

<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
  // Initialize dataLayer and gtag
  window.dataLayer = window.dataLayer || [];
  function gtag() { dataLayer.push(arguments); }
  gtag('js', new Date());

  // Configure GA4 with consent mode defaults (GDPR-friendly)
  gtag('consent', 'default', {
    analytics_storage: 'denied',    // Default: denied until user consents
    ad_storage: 'denied',
    wait_for_update: 500
  });

  gtag('config', 'G-XXXXXXXXXX', {
    send_page_view: false,          // Manual SPA page view tracking below
    debug_mode: false               // Set to true during development
  });

  // SPA page view tracking for WeWeb Vue.js navigation
  (function() {
    let lastTrackedPath = '';

    function sendPageView() {
      const path = window.location.pathname + window.location.search;
      if (path === lastTrackedPath) return;
      lastTrackedPath = path;

      gtag('event', 'page_view', {
        page_location: window.location.href,
        page_path: window.location.pathname,
        page_title: document.title,
        page_referrer: document.referrer
      });
    }

    // Track initial load
    window.addEventListener('load', sendPageView);

    // Track back/forward navigation
    window.addEventListener('popstate', sendPageView);

    // Intercept pushState (Vue Router uses this for navigation)
    const _pushState = history.pushState.bind(history);
    history.pushState = function(state, title, url) {
      _pushState(state, title, url);
      setTimeout(sendPageView, 100); // Small delay for page title update
    };

    // Intercept replaceState
    const _replaceState = history.replaceState.bind(history);
    history.replaceState = function(state, title, url) {
      _replaceState(state, title, url);
    };

    // Helper for custom events from WeWeb workflows
    // Call: window.trackEvent('button_click', { button: 'signup_hero' })
    window.trackEvent = function(eventName, params) {
      gtag('event', eventName, params || {});
    };
  })();
</script>
```

## Common mistakes

- **Not publishing the GTM container after making tag/trigger changes** — undefined Fix: GTM changes only take effect after you click Submit → Publish in GTM. Saving a tag in GTM does not deploy it. After publishing GTM, you do not need to republish WeWeb for GTM tag changes — only the initial GTM snippet installation requires WeWeb to be published.
- **Using 'All Pages' trigger only, which fires just once on SPA initial load and misses subsequent navigation** — undefined Fix: Add a 'History Change' trigger to your GA4 tag in GTM alongside the Initialization trigger. This fires on every WeWeb page navigation. Without it, GA4 only records the first page view and misses all subsequent navigation.
- **Double-counting page views by having both the GTM plugin and a manual GA4 script in Custom Code Head** — undefined Fix: Use only one method: either the GTM plugin OR the Custom Code Head injection. Never both. If you have both, GA4 will receive two page_view events for every page navigation.
- **Not testing with GTM Preview mode before publishing, leading to silent tracking failures** — undefined Fix: Always click Preview in GTM before Submit/Publish. GTM Preview shows exactly which tags fired on which events. If a tag does not fire, the debug panel shows which triggers were evaluated and why they did not match.

## Best practices

- Use the GTM plugin rather than direct GA4 head injection — GTM lets you update tracking without republishing WeWeb
- Always use GTM Preview mode to validate tags fire before publishing the GTM container to production
- Configure Consent Mode v2 in GTM for EU/GDPR compliance — set analytics_storage to denied by default and update to granted after user consent
- Use GA4 naming conventions for custom events: lowercase with underscores, descriptive verb-noun format (e.g., form_submit, video_play, signup_complete)
- Set up GA4 Conversions for your most important events (signup_complete, purchase, form_submit) so they appear in Conversion reports
- Test GA4 tracking in GA4 DebugView (Admin → DebugView) — it shows real-time events with full parameter details during testing
- Use the Segment plugin as an alternative to GTM if you want a customer data platform — Segment routes events to GA4, Mixpanel, Amplitude, and 300+ other tools from a single integration

## Frequently asked questions

### Why does GA4 only show one page view per session in my WeWeb app?

This is the classic SPA tracking problem. WeWeb navigation does not trigger browser page reloads, so the standard 'All Pages' GA4 trigger only fires once. You need a GTM History Change trigger (or equivalent) assigned to your GA4 tag. In GTM, create a new trigger with type 'History Change' and assign it to your GA4 tag alongside the Initialization trigger. This fires GA4 on every WeWeb page navigation.

### Does WeWeb's GTM plugin support separate GTM containers for development and production?

Yes. In the GTM plugin configuration (Plugins → Extensions → Google Tag Manager → Edit), you can enter different Container IDs for the Editor, Staging, and Production environments. This lets you test new tags in a development GTM container without affecting production analytics data.

### Can I use Google Analytics Universal Analytics (UA) instead of GA4 in WeWeb?

Universal Analytics was shut down in July 2024. All new tracking must use Google Analytics 4. If you have an old UA property, you need to create a new GA4 property in Google Analytics and reconfigure your GTM tags to use the GA4 Measurement ID (G-XXXXXXXXXX format) instead of the old UA Tracking ID (UA-XXXXXXXXX-X format).

### How do I track conversions like form submissions and sign-ups in GA4 via WeWeb?

In your WeWeb workflow, add a 'GTM - Push dataLayer event' action after a successful form submission with an event name like 'form_submit' and relevant parameters. In GTM, create a Custom Event trigger on 'form_submit' and a GA4 Event tag that fires on it. Then in GA4 Admin → Events, find your 'form_submit' event and click the star icon to mark it as a Conversion. GA4 Conversion reports will then track these events separately with conversion rate metrics.

---

Source: https://www.rapidevelopers.com/weweb-tutorial/weweb-google-analytics
© RapidDev — https://www.rapidevelopers.com/weweb-tutorial/weweb-google-analytics
