> Part of the walkerOS documentation. Project overview and full index: <https://www.walkeros.io/llms.txt>

# Google Analytics 4 (GA4)

<!-- -->

[Web](#)[ ](https://github.com/elbwalker/walkerOS/tree/main/packages/web/destinations/gtag)

<!-- -->

[Source code](https://github.com/elbwalker/walkerOS/tree/main/packages/web/destinations/gtag)[ ](https://www.npmjs.com/package/@walkeros/web-destination-gtag)

<!-- -->

[Package](https://www.npmjs.com/package/@walkeros/web-destination-gtag)

[Google Analytics 4 (GA4)](https://support.google.com/analytics/answer/10089681?hl=en\&ref_topic=14089939\&sjid=11701302784514925217-EU) is configured within the unified gtag destination. walkerOS loads the gtag script and forwards mapped events to GA4.

## Installation[​](#installation "Direct link to Installation")

```
npm install @walkeros/web-destination-gtag
```

```
import { startFlow } from '@walkeros/collector';
import { destinationGtag } from '@walkeros/web-destination-gtag';

await startFlow({
  destinations: {
    ga4: {
      code: destinationGtag,
      config: {
        settings: {
          ga4: {
            measurementId: 'G-XXXXXXXXXX',
          },
        },
      },
    },
  },
});
```

## Let a tag manager own the configuration[​](#let-a-tag-manager-own-the-configuration "Direct link to Let a tag manager own the configuration")

If a container (for example GTM) already configures your measurement ID, set `init: false`. walkerOS then skips the gtag bootstrap entirely, no `js`, no `config`, no script load, and only sends events, routed by `send_to`.

```
settings: {
  ga4: {
    measurementId: 'G-XXXXXXXX',
    init: false,
  },
}
```

This matters for attribution. A `config` command affects user and session identity for the rest of the page, so a second one arriving later than the container's own can disturb the session GA4 already established. When the container configures the tag, let it stay authoritative and put `server_container_url` and related settings on the container's tag rather than here.

## Serve gtag.js first-party[​](#serve-gtagjs-first-party "Direct link to Serve gtag.js first-party")

By default gtag.js loads from `googletagmanager.com`. To serve it from your own tagging server instead, set `scriptSrc` to the [tag serving path](https://developers.google.com/tag-platform/tag-manager/server-side/dependency-serving) configured in your server container. The path maps to the measurement ID inside the container, so the ID is not part of the URL.

```
settings: {
  ga4: {
    measurementId: 'G-XXXXXXXXXX',
    scriptSrc: 'https://example.com/metrics/tag_serving_path/',
    server_container_url: 'https://example.com/metrics',
  },
}
```

`server_container_url` routes measurement data and must **not** include the tag serving path. Setting it alone does not change where the script loads from, because serving gtag.js is a separate capability your container may not have. If `scriptSrc` fails to load, walkerOS falls back to `googletagmanager.com` so a misconfigured container degrades to working measurement rather than none.

## A page view needs no mapping[​](#a-page-view-needs-no-mapping "Direct link to A page view needs no mapping")

The gtag destination snake-cases an `entity action` event name into a GA4 event name automatically, so `page view` arrives in GA4 as `page_view` with no mapping at all. An unmapped `product add` would arrive as `product_add` carrying only `send_to`, which is why the ecommerce event below needs an explicit mapping.

## Add the ecommerce mapping[​](#add-the-ecommerce-mapping "Direct link to Add the ecommerce mapping")

Nest the mapping under the gtag destination to turn a `product add` event into the GA4 `add_to_cart` event. The product price becomes the GA4 `value`, the currency falls back to `EUR`, and the product is shaped into a GA4 `items` array via a `this` loop.

```
mapping: {
  product: {
    add: {
      name: 'add_to_cart',
      data: {
        map: {
          value: 'data.price',
          currency: { value: 'EUR', key: 'data.currency' },
          items: {
            loop: [
              'this',
              {
                map: {
                  item_id: 'data.id',
                  item_name: 'data.name',
                  quantity: { value: 1, key: 'data.quantity' },
                },
              },
            ],
          },
        },
      },
    },
  },
}
```

Pushing a `product add` event:

```
elb('product add', { id: 'ers', name: 'Everyday Ruck Snack', price: 420 });
```

produces the GA4 `add_to_cart` event:

```
gtag('event', 'add_to_cart', {
  value: 420,
  currency: 'EUR',
  items: [{ item_id: 'ers', item_name: 'Everyday Ruck Snack', quantity: 1 }],
  send_to: 'G-XXXXXXXXXX',
});
```

## Parameter names[​](#parameter-names "Direct link to Parameter names")

A parameter name carrying a character GA4 does not accept, a hyphen most commonly, is discarded on ingestion without an error. The destination therefore rewrites those characters to underscores before sending. Tagging `creative-type` under `include: ['data']` produces the parameter `data_creative-type`, which is sent as `data_creative_type` rather than going missing. Case is left alone, since GA4 treats parameter names case-sensitively.

Event names are never rewritten this way. `snakeCase` lowercases the event name and replaces its spaces with underscores; set it to `false` and the name is sent exactly as configured.

Two parameters are dropped rather than renamed:

| Parameter         | Why                                                                                                                                                         |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `source_platform` | Produced by `include` from `event.source.platform`. GA4 reads it as a manual campaign carrying no source or medium, which reports traffic as **Unassigned** |
| `user_id`         | Produced by `include` from `event.user.id`. GA4 takes identity through its own configuration and ignores the name as an event parameter                     |

Required ecommerce parameters such as `currency`, `value` and `transaction_id` are unaffected. To keep the platform value, map it to a name of your own:

```
data: { map: { platform: 'source.platform' } }
```

## Verify in GA4[​](#verify-in-ga4 "Direct link to Verify in GA4")

Copy your Measurement ID from GA4 > Admin > Data Streams and open your web stream. Watch Reports > Realtime to confirm the `page_view` event, then open Admin > DebugView to inspect the `add_to_cart` event and its parameters as they arrive.

## Configuration[​](#configuration "Direct link to Configuration")

This <!-- -->destination<!-- --> uses the standard <!-- -->destination<!-- --> config wrapper (consent, data, env, id, ...). For the shared fields see [destination<!-- --> configuration](https://www.walkeros.io/docs/destinations.md#configuration). Package-specific fields live under `config.settings` and are listed below.

## Settings[​](#settings "Direct link to Settings")

| Property               | Type                  | Description                                                                                                                            | More |
| ---------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| `como`                 | `boolean \| object`   | Consent mode configuration: false (disabled), true (use defaults), or custom mapping                                                   |      |
| `como_advanced`        | `boolean \| number`   | Advanced consent mode (non-EU): emit denied default at page load with wait\_for\_update (true=500ms, or a number of ms)                |      |
| `ga4`                  | `ga4`                 | GA4-specific configuration settings                                                                                                    |      |
| `measurementId*`       | `string`              | GA4 Measurement ID from Google Analytics                                                                                               |      |
| `debug`                | `boolean`             | Enable debug mode for GA4                                                                                                              |      |
| `pageview`             | `boolean`             | Enable automatic pageview tracking                                                                                                     |      |
| `server_container_url` | `string`              | Server-side GTM container URL                                                                                                          |      |
| `snakeCase`            | `boolean`             | Lowercase the event name and replace its spaces with underscores (like true). Applies to the event name only, never to parameter names |      |
| `transport_url`        | `string`              | Custom transport URL for GA4                                                                                                           |      |
| `data`                 | `any`                 | Custom data mapping configuration                                                                                                      |      |
| `ads`                  | `ads`                 | Google Ads specific configuration settings                                                                                             |      |
| `conversionId*`        | `string`              | Google Ads Conversion ID (required)                                                                                                    |      |
| `currency`             | `string`              | Currency code (ISO 4217, e.g., USD, EUR)                                                                                               |      |
| `data`                 | `any`                 | Custom data mapping (WalkerOS.Mapping.Value \| Values)                                                                                 |      |
| `enhancedConversions`  | `enhancedConversions` | Enhanced conversions: maps event fields to Google user\_data for improved measurement accuracy                                         |      |
| `email`                | `any`                 | Mapping value for user email                                                                                                           |      |
| `phone_number`         | `any`                 | Mapping value for user phone number                                                                                                    |      |
| `address`              | `address`             | Address mapping for enhanced conversions                                                                                               |      |
| `first_name`           | `any`                 | Mapping value for first name                                                                                                           |      |
| `last_name`            | `any`                 | Mapping value for last name                                                                                                            |      |
| `street`               | `any`                 | Mapping value for street address                                                                                                       |      |
| `city`                 | `any`                 | Mapping value for city                                                                                                                 |      |
| `region`               | `any`                 | Mapping value for region/state                                                                                                         |      |
| `postal_code`          | `any`                 | Mapping value for postal/zip code                                                                                                      |      |
| `country`              | `any`                 | Mapping value for country                                                                                                              |      |
| `gtm`                  | `gtm`                 | Google Tag Manager specific configuration settings                                                                                     |      |
| `containerId*`         | `string`              | GTM Container ID (required)                                                                                                            |      |
| `dataLayer`            | `string`              | Custom dataLayer variable name (default: dataLayer)                                                                                    |      |
| `domain`               | `string`              | Custom GTM domain for script loading                                                                                                   |      |
| `data`                 | `any`                 | Custom data mapping (WalkerOS.Mapping.Value \| Values)                                                                                 |      |

\* Required fields

## Mapping[​](#mapping "Direct link to Mapping")

Per-event rules under `config.mapping`. For the standard rule fields (consent, condition, data, batch, name, policy) see [mapping](https://www.walkeros.io/docs/mapping.md).

| Property | Type     | Description                              | More |
| -------- | -------- | ---------------------------------------- | ---- |
| `ga4`    | `ga4`    | GA4-specific event mapping               |      |
| `ads`    | `ads`    | Google Ads-specific event mapping        |      |
| `label`  | `string` | Conversion label for this specific event |      |
| `gtm`    | `gtm`    | GTM-specific event mapping               |      |

## Examples

### Add to cart

A product add event is mapped to the GA4 add\_to\_cart event with item details and value.

Event

```
{
  "name": "product add",
  "data": {
    "id": "ers",
    "name": "Everyday Ruck Snack",
    "color": "black",
    "size": "l",
    "price": 420
  },
  "context": {
    "shopping": [
      "intent",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [],
  "consent": {
    "functional": true
  },
  "id": "f5aebb26790ff263",
  "trigger": "click",
  "entity": "product",
  "action": "add",
  "timestamp": 1700000101,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "add_to_cart",
  "include": [
    "data"
  ],
  "data": {
    "map": {
      "currency": {
        "value": "EUR",
        "key": "data.currency"
      },
      "value": "data.price",
      "items": {
        "loop": [
          "this",
          {
            "map": {
              "item_id": "data.id",
              "item_variant": "data.color",
              "quantity": {
                "value": 1,
                "key": "data.quantity"
              }
            }
          }
        ]
      }
    }
  }
}
```

Out

```
gtag("event", "add_to_cart", {
  "currency": "EUR",
  "value": 420,
  "items": [
    {
      "item_id": "ers",
      "item_variant": "black",
      "quantity": 1
    }
  ],
  "data_id": "ers",
  "data_name": "Everyday Ruck Snack",
  "data_color": "black",
  "data_size": "l",
  "data_price": 420,
  "send_to": "G-XXXXXX-1"
})
```

### Enhanced conversions

enhancedConversions maps event fields into a gtag set user\_data call sent immediately before the conversion event.

Event

```
{
  "name": "order complete",
  "data": {
    "id": "0rd3r1d",
    "currency": "EUR",
    "shipping": 5.22,
    "taxes": 73.76,
    "total": 555,
    "customerEmail": "buyer@shop.com",
    "customerPhone": "+1234567890"
  },
  "context": {
    "shopping": [
      "complete",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "product",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "size": "one size",
        "price": 42
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "gift",
      "data": {
        "name": "Surprise"
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "864b2b26489a786d",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000109,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "PURCHASE_EC2",
  "settings": {
    "ads": {
      "label": "PURCHASE_EC2"
    }
  },
  "data": {
    "map": {
      "value": "data.total"
    }
  }
}
```

Out

```
gtag("set", "user_data", {
  "email": "buyer@shop.com",
  "phone_number": "+1234567890"
});

gtag("event", "conversion", {
  "send_to": "AW-123456789/PURCHASE_EC2",
  "currency": "EUR",
  "value": 555
})
```

### Google Ads init

Configures a Google Ads account via its conversionId. gtag already exists here, so no \`js\` is sent.

Event

```
{
  "settings": {
    "ads": {
      "conversionId": "AW-123456789",
      "currency": "EUR"
    }
  }
}
```

Out

```
gtag("config", "AW-123456789")
```

### Consent Mode v2

A walker consent command with marketing and functional granted updates gtag Consent Mode v2 parameters.

Event

```
{
  "marketing": true,
  "functional": true
}
```

Out

```
gtag("consent", "default", {
  "ad_storage": "denied",
  "ad_user_data": "denied",
  "ad_personalization": "denied",
  "analytics_storage": "denied"
});

gtag("consent", "update", {
  "ad_storage": "granted",
  "ad_user_data": "granted",
  "ad_personalization": "granted",
  "analytics_storage": "granted"
})
```

### GA4 init

Configures a GA4 property via its measurementId. gtag already exists here, so no \`js\` is sent: that would be a second, false initialisation signal.

Event

```
{
  "settings": {
    "ga4": {
      "measurementId": "G-XXXXXX-1"
    }
  }
}
```

Out

```
gtag("config", "G-XXXXXX-1", {})
```

### GA4 include all

Include flattens every event section into prefixed GA4 params, exposing data, context, user, source, and event fields.

Event

```
{
  "name": "page view",
  "data": {
    "domain": "www.example.com",
    "title": "walkerOS documentation",
    "referrer": "https://www.walkeros.io/",
    "search": "?foo=bar",
    "hash": "#hash",
    "id": "/docs/"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "pagegroup": "docs"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "ev-1700000106",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000106,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "1700000106abcdef1700000106abcdef",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "include": [
    "data",
    "context",
    "globals",
    "user",
    "source",
    "event"
  ]
}
```

Out

```
gtag("event", "page_view", {
  "data_domain": "www.example.com",
  "data_title": "walkerOS documentation",
  "data_referrer": "https://www.walkeros.io/",
  "data_search": "?foo=bar",
  "data_hash": "#hash",
  "data_id": "/docs/",
  "context_dev": "test",
  "globals_pagegroup": "docs",
  "user_device": "c00k13",
  "user_session": "s3ss10n",
  "source_type": "collector",
  "source_schema": "4",
  "source_count": 1,
  "source_trace": "1700000106abcdef1700000106abcdef",
  "source_release_default": "4.5.0",
  "event_entity": "page",
  "event_action": "view",
  "event_trigger": "load",
  "event_id": "ev-1700000106",
  "event_name": "page view",
  "event_timestamp": 1700000106,
  "event_timing": 3.14,
  "send_to": "G-XXXXXX-1"
})
```

### Ads conversion

An order complete event is sent as a Google Ads conversion with a configured label and transaction value.

Event

```
{
  "name": "order complete",
  "data": {
    "id": "0rd3r1d",
    "currency": "EUR",
    "shipping": 5.22,
    "taxes": 73.76,
    "total": 555
  },
  "context": {
    "shopping": [
      "complete",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "product",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "size": "one size",
        "price": 42
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "gift",
      "data": {
        "name": "Surprise"
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "66b93c938cf1b3cd",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000103,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "PURCHASE_CONV",
  "settings": {
    "ads": {
      "label": "PURCHASE_CONV"
    }
  },
  "data": {
    "map": {
      "value": "data.total"
    }
  }
}
```

Out

```
gtag("event", "conversion", {
  "send_to": "AW-123456789/PURCHASE_CONV",
  "currency": "EUR",
  "value": 555
})
```

### GTM dataLayer push

A page view event is pushed to window\.dataLayer for GTM with the mapped event name and parameters.

Event

```
{
  "name": "page view",
  "data": {
    "domain": "www.example.com",
    "title": "walkerOS documentation",
    "referrer": "https://www.walkeros.io/",
    "search": "?foo=bar",
    "hash": "#hash",
    "id": "/docs/"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "pagegroup": "docs"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "30d191241e1f6d3d",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000104,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "page_view",
  "settings": {
    "gtm": {}
  },
  "data": {
    "map": {
      "page_title": "data.title",
      "page_location": "data.domain"
    }
  }
}
```

Out

```
dataLayer.push({
  "event": "page_view",
  "page_title": "walkerOS documentation",
  "page_location": "www.example.com"
})
```

### GTM init

With script loading enabled the destination initializes the dataLayer, pushes the gtm.js start event, and loads the GTM container.

Event

```
{
  "loadScript": true,
  "settings": {
    "gtm": {
      "containerId": "GTM-XXXXXXX"
    }
  }
}
```

Out

```
dataLayer.push({
  "gtm.start": 1700000000000,
  "event": "gtm.js"
})
```

### Multi-tool push

A single order event fans out to GA4, Google Ads, and GTM from one mapping rule with per-tool settings.

Event

```
{
  "name": "order complete",
  "data": {
    "id": "0rd3r1d",
    "currency": "EUR",
    "shipping": 5.22,
    "taxes": 73.76,
    "total": 555
  },
  "context": {
    "shopping": [
      "complete",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "product",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "size": "one size",
        "price": 42
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "gift",
      "data": {
        "name": "Surprise"
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "77918b95c513d885",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000107,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "purchase",
  "include": [
    "data"
  ],
  "settings": {
    "ga4": {},
    "ads": {
      "label": "PURCHASE_CONV"
    },
    "gtm": {}
  },
  "data": {
    "map": {
      "value": "data.total",
      "currency": {
        "key": "data.currency",
        "value": "EUR"
      }
    }
  }
}
```

Out

```
gtag("event", "purchase", {
  "value": 555,
  "currency": "EUR",
  "data_id": "0rd3r1d",
  "data_currency": "EUR",
  "data_shipping": 5.22,
  "data_taxes": 73.76,
  "data_total": 555,
  "send_to": "G-XXXXXX-1"
});

gtag("event", "conversion", {
  "send_to": "AW-123456789/PURCHASE_CONV",
  "currency": "EUR",
  "value": 555,
  "data_id": "0rd3r1d",
  "data_currency": "EUR",
  "data_shipping": 5.22,
  "data_taxes": 73.76,
  "data_total": 555
});

dataLayer.push({
  "event": "purchase",
  "value": 555,
  "currency": "EUR",
  "data_id": "0rd3r1d",
  "data_currency": "EUR",
  "data_shipping": 5.22,
  "data_taxes": 73.76,
  "data_total": 555
})
```

### Page view

A page view event is forwarded as a GA4 page\_view event with no additional mapping.

Event

```
{
  "name": "page view",
  "data": {
    "domain": "www.example.com",
    "title": "walkerOS documentation",
    "referrer": "https://www.walkeros.io/",
    "search": "?foo=bar",
    "hash": "#hash",
    "id": "/docs/"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "pagegroup": "docs"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "d75d28698a71428a",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000102,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Out

```
gtag("event", "page_view", {
  "send_to": "G-XXXXXX-1"
})
```

### Purchase

An order complete event is mapped to the GA4 purchase event with transaction details and nested product items.

Event

```
{
  "name": "order complete",
  "data": {
    "id": "0rd3r1d",
    "currency": "EUR",
    "shipping": 5.22,
    "taxes": 73.76,
    "total": 555
  },
  "context": {
    "shopping": [
      "complete",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "product",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "size": "one size",
        "price": 42
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "gift",
      "data": {
        "name": "Surprise"
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "544404246e968e43",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000100,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "purchase",
  "include": [
    "data",
    "context"
  ],
  "data": {
    "map": {
      "transaction_id": "data.id",
      "value": "data.total",
      "tax": "data.taxes",
      "shipping": "data.shipping",
      "currency": {
        "key": "data.currency",
        "value": "EUR"
      },
      "items": {
        "loop": [
          "nested",
          {
            "condition": {
              "$code": "e=>S(e)&&\"product\"===e.entity"
            },
            "map": {
              "item_id": "data.id",
              "item_name": "data.name",
              "quantity": {
                "key": "data.quantity",
                "value": 1
              }
            }
          }
        ]
      }
    }
  }
}
```

Out

```
gtag("event", "purchase", {
  "transaction_id": "0rd3r1d",
  "value": 555,
  "tax": 73.76,
  "shipping": 5.22,
  "currency": "EUR",
  "items": [
    {
      "item_id": "ers",
      "item_name": "Everyday Ruck Snack",
      "quantity": 1
    },
    {
      "item_id": "cc",
      "item_name": "Cool Cap",
      "quantity": 1
    }
  ],
  "data_id": "0rd3r1d",
  "data_currency": "EUR",
  "data_shipping": 5.22,
  "data_taxes": 73.76,
  "data_total": 555,
  "context_shopping": "complete",
  "send_to": "G-XXXXXX-1"
})
```
