Skip to main content

GA4

Server Source code Package

Decoder transformer that turns Google Analytics 4 Measurement Protocol v2 hits (/g/collect, /mp/collect) into walkerOS events. Drop it in a server source's before chain to ingest existing gtag/Google Tag traffic without changing the front-end. One HTTP request can carry many GA4 events; the transformer returns one walkerOS event per GA4 event in the hit.

This is the v1 release (0.1.0) with an explicit scope: server-side decoding via source-express, GA4 v2 only, replace-not-merge mapping semantics. See Caveats and Roadmap for the boundaries.

Installation

Loading...

Wire it up

The transformer reads ctx.ingest.url (required) and ctx.ingest.body (optional) from the source it sits in front of. The recommended pairing is @walkeros/server-source-express:

{
"version": 4,
"flows": {
"default": {
"config": { "platform": "server" },
"sources": {
"http": {
"package": "@walkeros/server-source-express",
"config": {
"ingest": {
"url": "req.url",
"body": "req.body"
}
},
"before": "ga4"
}
},
"transformers": {
"ga4": { "package": "@walkeros/transformer-ga4" }
},
"destinations": {
"log": { "package": "@walkeros/destination-demo" }
}
}
}
}

Ingest contract

The transformer expects the source to populate ctx.ingest with these keys:

KeyTypeRequiredNotes
urlstringyesFull request URL including the query string.
bodystringnoRaw POST body. Multi-event batches are \n-separated lines.

If url is missing or not a string the transformer drops the event silently. If body is JSON-parsed by the source before reaching the transformer, pass the original raw string through or skip the transformer.

Configuration

This transformer uses the standard transformer config wrapper (consent, data, env, id, ...). For the shared fields see transformer configuration. Package-specific fields live under config.settings and are listed below.

Settings

This package has no package-specific settings.

Mapping

This package does not define custom rule-level settings. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.

Examples

Add to cart

A GA4 add_to_cart hit decoded to a walkerOS product add event with currency and value.

Event
Out

Batched POST (fan-out)

A single POST request carrying two newline-separated events fans out into two walkerOS events.

Event
Out

Begin checkout

A GA4 begin_checkout hit decoded to a walkerOS order start event with currency, value, and coupon.

Event
Out

Consent denied (gcs=G100)

A page_view hit with gcs=G100 still maps, with consent.{marketing,analytics} both false on the resulting event.

Event
Out

Custom event (* fallback)

Unknown GA4 event names hit the * fallback rule and surface as a ga4 track event carrying the original name.

Event
Out

Login

A GA4 login hit decoded to a walkerOS session login event with the auth method.

Event
Out

Page view

A standard GA4 page_view hit decoded to a walkerOS page view with id, title, and referrer.

Event
Out

Purchase (canary)

A GA4 purchase hit decoded to a walkerOS order complete event with id, currency, total, tax, shipping, and coupon.

Event
Out

Scroll

A GA4 scroll hit decoded to a walkerOS page scroll event with the percent_scrolled value.

Event
Out

Search

A GA4 search hit decoded to a walkerOS search submit event carrying the search term.

Event
Out

user_engagement (ignored)

Auto-fired GA4 user_engagement events are dropped by default — the transformer returns false.

Event
Out

View item

A GA4 view_item hit decoded to a walkerOS product view event with currency and value.

Event
Out

Default mappings

transformer-ga4 ships with default mappings for 33 standard GA4 event names. Out of the box, you get pageviews, ecommerce, list/promotion, engagement, and auth events mapped to walkerOS's entity-action naming.

Page / scroll / click

GA4 (en)walkerOS (name)Fields
page_viewpage viewid, title, referrer
scrollpage scrollpercent
clicklink clickurl, domain, outbound
file_downloadfile downloadname, extension, url

Ecommerce

GA4 (en)walkerOS (name)Fields
view_itemproduct viewcurrency, value
add_to_cartproduct addcurrency, value
remove_from_cartproduct removecurrency, value
view_cartcart viewcurrency, value
begin_checkoutorder startcurrency, value, coupon
add_shipping_infoorder shippingcurrency, value, tier
add_payment_infoorder paymentcurrency, value, type
purchaseorder completeid, currency, total, tax, shipping
refundorder refundid, currency, total
add_to_wishlistwishlist addcurrency, value

List / promotion

GA4 (en)walkerOS (name)Fields
view_item_listlist viewid, name
select_itemproduct clicklist_id, list_name
view_promotionpromotion viewreads from items[0]
select_promotionpromotion clickreads from items[0]
select_contentcontent selecttype, id
GA4 (en)walkerOS (name)Fields
video_startvideo starttitle, duration, current, percent
video_progressvideo progresssame as video_start
video_completevideo completesame as video_start
form_startform startid, name, destination
form_submitform submitid, name, destination
searchsearch submitterm

Auth / lead / share

GA4 (en)walkerOS (name)Fields
loginsession loginmethod
sign_upsession signupmethod
generate_leadlead generatecurrency, value
sharecontent sharemethod, type, id

Auto-fired noise (dropped by default)

GA4 (en)Behavior
user_engagementignore: true
session_startignore: true
first_visitignore: true

These events are emitted automatically by gtag and rarely carry analytics intent. Override the rule if you need them.

Fallback

GA4 (en)walkerOS (name)Fields
'*'ga4 trackdata.event_name = original en

Any GA4 event name not listed above falls through to '*' and produces a generic ga4 track walkerOS event. Override '*' to change the fallback rule globally.

Override a default field

User config replaces the matching default rule per event name. Other events keep their defaults. To swap a field on purchase:

{
"transformers": {
"ga4": {
"package": "@walkeros/transformer-ga4",
"config": {
"settings": {
"mapping": {
"purchase": {
"name": "order complete",
"data": {
"map": {
"id": "params.ep.transaction_id",
"total": "params.epn.value",
"currency": "params.ep.currency",
"coupon": "params.ep.promo_code"
}
}
}
}
}
}
}
}
}

Because v1 uses replace semantics, the entire purchase rule is taken from user config: copy any default fields you want to keep. Additive per-field merge is on the roadmap.

Drop an event

Set ignore: true on any key to prevent it from being emitted:

"settings": {
"mapping": {
"click": { "ignore": true }
}
}

This is how user_engagement, session_start, and first_visit are silenced by default.

Custom events

Two patterns:

1. Override '*' to change the global fallback for unknown GA4 event names:

"settings": {
"mapping": {
"*": {
"name": "custom event",
"data": { "map": { "event_name": "name" } }
}
}
}

2. Add a specific key for an event you fire via gtag('event', '<your_name>', ...):

"settings": {
"mapping": {
"newsletter_subscribe": {
"name": "newsletter signup",
"data": { "map": { "source": "params.ep.source" } }
}
}
}

Tracking ID filtering

By default only Measurement IDs starting with G- are accepted; Ads (AW-) and DC (DC-) hits are dropped. Widen via a string regex in settings.tidPattern:

"settings": {
"tidPattern": "^(G|AW|DC)-"
}

The string is compiled to a RegExp at init time.

Caveats

  • Replace semantics, not merge. A user mapping rule fully replaces the matching default rule. There is no per-field merge inside data.map in v1.
  • GA4 v2 only. Assumes the v2 Measurement Protocol layout (ep., epn., up., upn., prN, gcs). v1 is out of scope.
  • G- tids only by default. Override tidPattern to capture Ads and DC traffic.
  • Basic gcs only. Maps G1XX to marketing/analytics booleans. Functional/preferences flags and the newer gcd parameter are not decoded.
  • Body must be raw text. The transformer parses POST bodies as URL-encoded form lines. Pre-parsed JSON bodies will not decode.
  • Ingest contract is required. Source wiring must populate ctx.ingest.url (required) and ctx.ingest.body (optional) for batched hits.

Roadmap

  • Additive per-field merge so partial overrides extend the default rule instead of replacing it
  • Web ingest via interception sources for capturing gtag traffic from the browser
  • More vendor decoders (Segment, Snowplow, Adobe) following the same before-chain pattern
  • Richer consent decoding (gcd, functional/preferences flags)

Next steps

💡 Need implementation support?
elbwalker offers hands-on support: setup review, measurement planning, destination mapping, and live troubleshooting. Book a 2-hour session (€399)