IngestionGA4 gtag Inbound

GA4 gtag Inbound

If your site already runs Google Analytics 4 through gtag.js, Datafly Signal can receive those hits directly. You set gtag’s server_container_url to your Signal collection endpoint and gtag sends every event to Signal instead of to Google. Signal translates each hit into a standard Signal event and runs it through your pipeline, so it reaches GA4 and every other integration you have configured.

This is a migration first step, not the end state. gtag.js still loads from Google, so ad blockers that block googletagmanager.com still stop these hits. Use it to get your existing tagging flowing through Signal on day one, then move to the first-party Datafly.js collector as described in Migrating from gtag.js.

Set it up

Turn on GA4 inbound for the pipeline

In the management UI, open Pipelines → your pipeline → Settings → GA4 inbound (gtag). Switch it on and, optionally, list the GA4 measurement IDs (G-XXXXXXXXXX) this pipeline should accept. Save.

Hits are refused until GA4 inbound is on. When you list measurement IDs, hits for any other GA4 property are refused too.

Point gtag at Signal

Copy the server_container_url shown on the card into your gtag config:

gtag('config', 'G-XXXXXXXXXX', {
  server_container_url: 'https://collect.yourdomain.com/ga/<pipeline_key>'
});

gtag adds /g/collect to that URL, so hits arrive at https://collect.yourdomain.com/ga/<pipeline_key>/g/collect. If you use Google Tag Manager, set the same value as the server_container_url configuration parameter on your Google tag.

Add a GA4 integration to the pipeline

Once hits go to Signal they no longer go to Google directly. Add the Google Analytics 4 integration to the pipeline so the events are delivered to your GA4 property.

Check events in the Event Debugger

Turn on debug mode for the pipeline and browse your site. gtag hits appear in the Event Debugger like any other event, with context.library.name set to gtag. If hits are refused, the debugger shows why (for example, GA4 inbound switched off or a measurement ID that isn’t on the list).

⚠️

Your collection endpoint should be a first-party subdomain of your site (for example collect.yourdomain.com), the same one the Datafly.js collector uses. The pipeline’s allowed-domains list still applies to gtag hits.

How hits are translated

gtag sends shared parameters on the URL and, when it batches, one event per line in the request body. Signal merges the two for each event and maps them as follows.

Events

gtagSignal event
en=page_viewtype page, event page (the same as datafly.page())
any other entype track, event name unchanged (for example add_to_cart, purchase, scroll)
ep.<name>properties.<name> (string)
epn.<name>properties.<name> (number)
up.<name> / upn.<name>properties.user_properties.<name>
cuproperties.currency
pr1prNproperties.items[] (see below)
_dbg=1 or ep.debug_modeproperties.debug_mode = true
tidproperties.ga_measurement_id
_pproperties.ga_page_load_id

Identity

gtagSignal
cidcontext.vendor_ids.ga_client_id, and stored under the visitor’s identity
uiduser_id

The anonymous ID is your existing _dfid cookie when there is one (for example when Datafly.js also runs on the site). Otherwise Signal derives a stable anonymous ID from the GA client ID and sets the _dfid cookie, persistent only when the hit’s consent allows it.

Page, device and session

gtagSignal
dlcontext.page.url, plus path and search
dtcontext.page.title
drcontext.page.referrer
utm_* in dlcontext.campaign
click IDs in dl (gclid, fbclid, msclkid …)click_ids, the same list Datafly.js captures
ulcontext.locale
srcontext.screen.width / height
uap, uapv, uamcontext.device.os, os_version, model
sidcontext.session.id (converted to milliseconds)
sctcontext.session.number
_ss, _nsicontext.session.is_new
_fvcontext.session.is_first_ever
segcontext.session.engaged
_etcontext.session.engagement_time

IP address, user agent, geolocation and network come from the request, exactly as for collector events.

gcs and gcd (Google Consent Mode) are decoded into context.consent.google (ad_storage, analytics_storage, ad_user_data, ad_personalization). Signal also sets the consent categories your integrations are gated on:

  • analytics follows analytics_storage
  • marketing is granted only when ad_storage is granted and ad_user_data is not denied

A hit with no Consent Mode signal is treated like a collector event from a pipeline with no consent provider.

Ecommerce items

Each prN parameter becomes one entry in properties.items, in the GA4 item schema:

Item keyFieldItem keyField
iditem_idlnitem_list_name
nmitem_nameliitem_list_id
britem_brandafaffiliation
ca, c2c5item_categoryitem_category5cpcoupon
vaitem_variantdsdiscount
prpricelolocation_id
qtquantitypi, pnpromotion_id, promotion_name
lpindexcn, cscreative_name, creative_slot

Custom item parameters (k0/v0 pairs) become fields named after the key. Event-level ecommerce parameters such as ep.transaction_id, epn.value, epn.tax and epn.shipping arrive as ordinary properties.

Limits and behaviour

  • The endpoint accepts GET and POST and returns 204 No Content.
  • Up to 50 events per request and 200 items per event. Bodies over 1 MB are refused.
  • Pipeline rate limits, monthly quota, IP blocklist and allowed domains apply as for any collector traffic. A GET hit without an Origin header is checked against its Referer.
  • gtag cannot sign requests or send challenge tokens, so server-type pipelines and pipelines that require challenge tokens refuse gtag hits.
  • gtag doesn’t report a browser timezone. Bot detection doesn’t count that (or a missing session on cookieless pings) against gtag hits.