walkeros-create-cmp-so…
A CMP source is a specialized walkerOS source that listens to a consent management platform's events and translates consent…
`@walkeros/transformer-ga4` decodes Google Analytics 4 Measurement Protocol v2 hits (`/g/collect`, `/mp/collect`) into walkerOS events. It sits in a server source's `before` chain, reads the raw HTTP request via `ctx.ingest`, and returns one walkerOS event per GA4 event in the
$ npx -y skills add elbwalker/walkerOS --skill walkeros-using-transformer-ga4 --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/walkeros-using-transformer-ga4Context preview
The summary Claude sees to decide when to auto-load this skill.
`@walkeros/transformer-ga4` decodes Google Analytics 4 Measurement Protocol v2 hits (`/g/collect`, `/mp/collect`) into walkerOS events. It sits in a server source's `before` chain, reads the raw HTTP request via `ctx.ingest`, and returns one walkerOS event per GA4 event in the
name: walkeros-using-transformer-ga4 description: Use when wiring `@walkeros/transformer-ga4` into a server flow, overriding default GA4 event mappings, dropping events, adding custom event keys, or troubleshooting GA4 Measurement Protocol decoding. Covers the `before`-chain wiring contract, configuration recipes, and per-field patching with extend/remove.
`@walkeros/transformer-ga4` decodes Google Analytics 4 Measurement Protocol v2 hits (`/g/collect`, `/mp/collect`) into walkerOS events. It sits in a server source's `before` chain, reads the raw HTTP request via `ctx.ingest`, and returns one walkerOS event per GA4 event in the hit (one hit can carry many events).
Boundaries: server-side decoding in front of a server source, GA4 v2 only, `G-` tids only by default. Per-field patching via `extend`/`remove` is supported.
**Pick the source by runtime before copying the example below.** gtag.js can send several events in one POST body (one per line, as `text/plain`), so the source must keep a non-JSON body as `ingest.body`. These server sources do:
`walkeros/flow` image serve. A `text/plain` body that is valid JSON is parsed; any other `text/plain` body reaches the decoder as the raw string.
`port`, for a runtime that calls it (Cloudflare Workers, Deno, Bun, Node.js 18+ with a fetch adapter), e.g. with `collector` from `startFlow`:
import { Source } from '@walkeros/core';
import type { SourceFetch } from '@walkeros/server-source-fetch';
export default {
fetch: Source.getSource<SourceFetch.Types>(collector, 'http').push,
};`runneros` and the `walkeros/flow` image cannot serve it (they only mount a source's Node `httpHandler`).
Functions.
POST without a body with 400, so body-less single-event hits are lost there.
The other sources take the same `ingest` and `before` config as the express example. The fetch source also takes `paths`; none of them takes `port`.
{
"version": 4,
"flows": {
"default": {
"config": { "platform": "server" },
"sources": {
"http": {
"package": "@walkeros/server-source-express",
"config": {
"settings": {
"port": 8080,
"paths": ["/g/collect"]
},
"ingest": {
"map": {
"url": { "key": "url" },
"path": { "key": "path" },
"method": { "key": "method" },
"body": { "key": "body" }
}
}
},
"before": "ga4"
}
},
"transformers": {
"ga4": { "package": "@walkeros/transformer-ga4" }
},
"destinations": {
"log": { "package": "@walkeros/destination-demo" }
}
}
}
}**Wiring rules:**
gtag.js sends to `/g/collect`, so set `settings.paths` to `["/g/collect"]` (or the full path, if the collector URL carries a path prefix). Without it every GA4 hit gets a 404.
`gtag('config', 'G-XXXXXXXXXX', { server_container_url: 'https://collect.example.com' })`. gtag.js appends `/g/collect`. With the walkerOS gtag destination, set `settings.ga4.server_container_url` (or `settings.ga4.transport_url`). Hits then go to the collector instead of Google. The `/g/collect` suffix, the body-less single-event POST, and one-line-per-event batches are gtag.js behaviour, not a walkerOS contract: confirm them in the browser Network tab.
request without GA4 parameters is dropped. If the source also receives walkerOS events (for example on `/collect`), gate the chain: `"before": { "match": { "key": "ingest.path", "operator": "eq", "value": "/g/collect" }, "next": "ga4" }`.
through `server-source-express` as the raw `text/plain` string, alongside GET and body-less POST hits. A body sent as `application/json` must be valid JSON, or express answers 400 before the decoder runs.
Decoding is a pre-collector concern: GA4 hits are not yet walkerOS events.
`ctx.ingest.body` (optional, string). Raw text body only: pre-parsed JSON will not decode. The express, fetch, GCP and AWS server sources keep a non-JSON `text/plain` body (gtag's batched POST) as the raw string in `ingest.body`; only a body that parses as JSON arrives parsed.
**Common mistake:** `config.ingest` must be the `map` operator with direct field paths on the request scope (no `req.` prefix), e.g. `{ "map": { "url": { "key": "url" } } }`. The bare `{ "url": "req.url" }` form is silently inert: without a `map` operator no field is extracted, so `ctx.ingest` stays empty, the decoder reads no `url`, and the hit is dropped.
This wiring c
From browser to BigQuery and ad platforms - warehouse-native, and ready for AI agents via MCP.
A CMP source is a specialized walkerOS source that listens to a consent management platform's events and translates consent…
Use when creating a new walkerOS destination to send events to a vendor or API (GA4/gtag, Meta/Facebook Pixel, Mixpanel,…
Use when creating a new walkerOS source to capture events (browser source, dataLayer interception, server/HTTP source, webhook…
| Symptom | Likely Cause | Check | | ---------------------------------- | ---------------------------- |…
Read [understanding-mapping](../walkeros-understanding-mapping/SKILL.md) first for core concepts.