Google Data Manager is Google's unified data ingestion service for advertising and measurement. Its Events service (events:ingest) accepts server-side conversion and engagement events and fans them out to multiple Google products — Google Ads, Google Analytics 4 (GA4), and Google Marketing Platform Floodlight configurations (Campaign Manager 360 / Display & Video 360) — from a single API call. This MetaRouter Starter Kit, "Google Data Manager - Events," sends full-funnel web and app events to the events:ingest endpoint with SHA-256 hashed user identifiers, Google ad identifiers, cart data, and per-destination routing.
Product Type: Advertising
Integration Type: Starter Kit & ID Sync
Event Source Type: Web and/or Mobile Browser and/or Mobile App
Event Scope: Full-Funnel Events
- Sends full-funnel events (page views, product and cart activity, checkout, purchases, refunds, promotions) to the Google Data Manager
events:ingest endpoint using an HTTP POST with an OAuth2 JWT bearer token.
- Fans out one event stream to multiple Google destinations — GA4, Google Ads, and Floodlight — in a single request via the
destinations[] array and per-event destinationReferences.
- Attaches SHA-256 hashed user identifiers (email, phone, and address components) plus Google ad identifiers (
gclid, wbraid, dclid, matchId, mobileDeviceId) to improve conversion matching.
- Carries conversion value and count, currency, cart items, and additional GA4 event parameters per event.
- Derives event source (
WEB or APP) from the incoming context and maps the mobile advertising ID for app events.
- Ships with global consent signals set to granted and HEX encoding for hashed identifiers.
- The integration only forwards events that carry at least one usable identifier — a Google click ID (
gclid, wbraid, dclid), GA4 clientId, mobile advertising ID, or hashed user data (email, phone, or full name with postal code and country). Events with none of these are filtered out before delivery.
- PII-only conversions (hashed user identifiers with no click or device ID) are supported only by Google Ads. Floodlight and GA4 require at least one of
gclid, matchId, dclid, impressionId, mobileDeviceId, or encryptedUserIds, and reject conversions without one.
validateOnly is set to false in the global enrichments, so the kit ships ready to send live events. Set it to true to validate requests without executing them — the API checks each request and returns only errors, not results. Useful for schema and configuration testing.
- The kit sends a single event stream to several Google platforms at once. The vendor configures one entry per target platform in the
destinations array in the global Lua, and each destination is addressed by its operatingAccount.accountType, accountId, and productDestinationId. If the vendor does not use a given platform, that entry must be removed from the destinations Lua.
- Destination-to-event relationship: one GA4 destination covers all events, while Google Ads and Floodlight require one destination per event because each event maps to a distinct conversion action (Google Ads) or activity (Floodlight).
- GA4 destinations are addressed by
eventName, which is required for GA4 events; Google Ads, Display & Video 360, and Floodlight destinations are addressed by the conversion action ID (Google Ads) or Floodlight activity ID set as productDestinationId.
- To add a new destination, choose the platform, add a
destination(...) line with a unique reference (the reference provides uniqueness when credentials are shared), then add that reference to the event's destinationReferences array. To remove one, delete the destination(...) line and remove its value from destinationReferences.
- To send an event to all destinations in a request,
destinationReferences does not need to be set; omitting it defaults to every destination listed.
- The
page event's name is taken from MetaRouter's Analytics.js event due to GA4 naming rules, and the page event is treated as a custom event for GA4.
- Use GA4's official parameter names for
parameterName in additionalEventParameters where possible, as recommended by Google.
gclid, wbraid, dclid, and clientId are web-only and are sourced from browser-side providers (gtag.js, Google Ads, CM360, GA4). Mobile (iOS/Android) events still deliver to the Data Manager API using mobileDeviceId with hashed user identifiers (email, phone, address) or matchId; these identifiers can also be passed directly on the event payload without relying on the sync.
encoding is required only when the request includes UserData uploads; this kit sets it to HEX. Email, phone, and name fields are SHA-256 hashed before sending.
- Within a single
UserData identifier, only one of emailAddress, phoneNumber, or address can be set.
unitPrice must exclude tax, shipping, and order-wide discounts, but include item-level discounts.
cartData requires the merchantProductId field for Floodlight and for Google Ads conversions that are not store sales; without it, the API silently strips all product-level data from the conversion.
- In this starter kit,
merchantProductId is mapped only on Order Completed: it is the sole cart event routed to Floodlight and Google Ads (via its destinationReferences). The other cart events go to GA4 only, which does not require it. If you route another cart event to Floodlight or Google Ads, add merchantProductId to its items as well.
- The kit sets
event.consent.adUserData and event.consent.adPersonalization to CONSENT_GRANTED statically; confirm this matches the pipeline's consent enforcement.
- Google does not require an upload delay for identifier matching; there is no processing delay for Google Ads conversions. For Floodlight online conversions, allow approximately two hours before editing a conversion through the API.
- This kit uses a batch size of 500.
- A single request can contain at most 10
Destination resources in the destinations list and at most 10 user identifiers in the UserData for each event.
- Diagnostics cannot be retrieved for requests that have
validateOnly set to true; the kit must be switched out of validate-only mode before request status can be polled.
- GA4 events must have an
eventTimestamp within the last 72 hours, and an event can reference only one GA4 destination — if destinationReferences is unset or has multiple entries referring to Google Analytics destinations, the event is rejected with MULTIPLE_DESTINATIONS_FOR_GOOGLE_ANALYTICS_EVENT.
- GA4 rejects reserved event names with
INVALID_EVENT_NAME, so custom names must follow GA4 naming rules.
- Each Google Cloud project is limited to 100,000
IngestionService requests per day and 300 requests per minute; exceeding the limits returns RESOURCE_EXHAUSTED with HTTP status 429 Too Many Requests.
- Sync Available: Yes
- Required for Starter Kit: Yes — the Google Tag (decoupled) sync populates the
clientId, gclid, wbraid, and dclid values that the integration reads from context.providers. The matchId (MetaRouter anonymousId) is available without the sync, but GA4 web-stream matching and Google Ads/Floodlight click attribution depend on the sync-captured values.
- Prerequisites: Parent Google Tag Settings configured and deployed before any child sync; relevant account identifiers (GA4 Measurement ID, Google Ads ID with conversion labels, and/or CM360 Floodlight IDs); consent categories configured in the MetaRouter UI.
- Documentation: See Additional Google Tag (Decoupled) Documentation
- In the decoupled model, Google Tag Settings acts as a parent that loads the gtag.js library, and each Google product (GA4, Google Ads, CM360) is configured as an independent child sync beneath it.
- The GA4 child sync captures the GA4 client ID, session information, and Google click identifiers (
gclid, dclid, wbraid), which the integration reads server-side under context.providers.
- The Google Ads child sync fires conversion events, while the CM360 child sync registers the MetaRouter anonymous ID (
matchId) with Campaign Manager 360 so it can later be matched to server-side conversions.
- Consent categories set in the MetaRouter UI gate when each sync fires, and captured identifiers are appended to the server-side event under
context.providers.
- To collect the sync values (e.g.,
clientId, gclid, wbraid, dclid), you must implement the Google Tag (decoupled) parent and the required child syncs (GA4, Google Ads, and/or CM360). The parent Google Tag Settings must be deployed before any child sync will function. Refer to the following documentation to complete the setup: Google Tag Decoupled - ID Sync Guide.
- Create a Google Cloud project, enable the Data Manager API, and create a service account with the datamanager scope. Grant the service account's email access to each destination (for GA4, add it as a user on the property). Then collect:
- Service account email
- RSA private key (PEM)
- Each destination's account type, account ID, and productDestinationId (GA4 Measurement ID, Google Ads conversion action ID, or Floodlight activity ID)
- For how to create a service account, configure the datamanager scope, and grant destination access, see Set up API Access.
- For details on accountType, accountId, and productDestinationId, see Configure Destinations and the Destination Resource reference.
- Note: For a step-by-step walkthrough of the Google Ads side — creating the service account, enabling the API, granting access, and creating conversion actions — see Google Ads Setup for Data Manager.
- From the integration library, add a Google Data Manager - Events integration. Then, fill out the Connection Parameters:
| Connection Parameter | Description |
|---|
API_VERSION | API version segment in the endpoint URL. Defaults to v1. |
SERVICE_ACCOUNT_EMAIL | Service account email used as the JWT issuer (iss) for OAuth2 authentication. |
PRIVATE_KEY | RSA private key (PEM) used to sign the OAuth2 JWT assertion. |
- MetaRouter provides all of the event mappings that Google Data Manager - Events integrations typically require. You may add custom events, parameters, or mappings in accordance with Google's API documentation.
- In the Pipelines tab, add your Google Data Manager - Events integration.
- Select the correct integration revision.
- Click Add Integration to finalize deployment.
Global mappings will be applied to all events. If your parameter names do not match the Expected Inputs provided, you will need to overwrite the Inputs provided with your own.
| Output Key | Description | Expected Input |
|---|
event.consent.adUserData | String: Consent signal for ad user data. | Enrichment – CONSENT_GRANTED |
event.consent.adPersonalization | String: Consent signal for ad personalization. | Enrichment – CONSENT_GRANTED |
encoding Required | String: Encoding of hashed user identifiers; required for UserData uploads. | Enrichment – HEX |
validateOnly | Boolean: When true, validates requests without executing them; returns only errors. | Enrichment – false |
destinations Required | Array: Destination objects that receive the events. | Expression – builds destination(reference, accountType, accountId, productDestinationId) entries for ga4, google_ads_purchase, google_ads_page, floodlight_purchase, floodlight_page |
event.adIdentifiers.gclid | String: Google click ID. | Expression – context.providers.CM360.gclid or googleGtag gclid |
event.adIdentifiers.wbraid | String: iOS web-to-app click identifier. | Expression – context.providers.googleAds.wbraid or googleGtag wbraid |
event.adIdentifiers.dclid | String: Display click ID. | Expression – context.providers.CM360.dclid or googleGtag dclid |
event.adIdentifiers.matchId | String: Match ID used to join this event with a prior event. | anonymousId |
event.adIdentifiers.landingPageDeviceInfo.ipAddress | String: Landing-page device IP address. | context.ip |
event.adIdentifiers.landingPageDeviceInfo.userAgent | String: Landing-page device user agent. | context.userAgent |
event.adIdentifiers.landingPageDeviceInfo.languageCode | String: ISO 639-1 language code. | Expression – SPLIT of context.locale |
event.transactionId | String: Unique identifier for the event. | messageId |
event.eventTimestamp Required | String: RFC 3339 timestamp of when the event occurred. | Expression – input.timestamp or input.originalTimestamp |
event.eventSource | String: Enum WEB or APP. | Expression – 'APP' if context.app.name, context.device.type, or context.os.name, else 'WEB' |
event.userData.userIdentifiers | Array: SHA-256 hashed user identifiers. | Expression – hashes traits.email, traits.phone, and address (givenName from firstName, familyName from lastName, postalCode, regionCode via TO_ISO_COUNTRY(country)) |
event.adIdentifiers.mobileDeviceId | String: Mobile advertising ID (IDFA/AAID). | context.device.advertisingId |
event.clientId | String: GA4 web client instance identifier. | Expression – googleAnalytics4.clientID or parsed from googleGtag ga cookie |
event.userId | String: Advertiser-defined user identifier. | userId |
event.destinationReferences | Array: Default destination routing references. | Expression – {"ga4"} |
event.currency | String: Currency code for monetary values. | properties.currency |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – page |
event.destinationReferences | Array: Destination routing references. | Expression – {"ga4","floodlight_page","google_ads_page"} |
event.additionalEventParameters | Array: GA4 event parameters. | Expression – page_location, page_title, page_referrer, search |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – purchase |
event.destinationReferences | Array: Destination routing references. | Expression – {"ga4","floodlight_purchase","google_ads_purchase"} |
event.conversionValue | Float: Conversion value. | properties.revenue |
event.conversionCount | Integer: Conversion quantity. | Expression – sum of product quantities |
event.transactionId | String: Unique identifier for the event; overrides the global messageId for purchases. | properties.order_id |
event.additionalEventParameters | Array: GA4 event parameters. | Expression – tax, shipping |
event.cartData | Object: Cart items, Merchant Center ID, and event-level coupon codes. | Expression – merchantId (ADD_MERCHANT_ID_HERE placeholder); couponCodes from properties.coupon; items map item_name, item_category; itemId and merchantProductId from product_id, quantity, unitPrice |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – search |
event.additionalEventParameters | Array: GA4 event parameters. | Expression – search_term from properties.query |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – select_item |
event.conversionValue | Float: Conversion value. | Expression – TOTAL_VALUE(properties) |
event.conversionCount | Integer: Conversion quantity. | properties.quantity |
event.cartData.items | Array: Cart items. | Expression – item_name, item_category, item_variant, item_brand, discount, index from position, coupon; itemId from product_id, quantity, unitPrice |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – add_to_cart |
event.conversionValue | Float: Conversion value. | Expression – TOTAL_VALUE(properties) |
event.conversionCount | Integer: Conversion quantity. | properties.quantity |
event.cartData.items | Array: Cart items. | Expression – item_name, item_category, item_variant, item_brand, discount, index from position, coupon; itemId from product_id, quantity, unitPrice |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – add_to_wishlist |
event.conversionValue | Float: Conversion value. | Expression – TOTAL_VALUE(properties) |
event.conversionCount | Integer: Conversion quantity. | properties.quantity |
event.cartData.items | Array: Cart items. | Expression – item_name, item_category, item_variant, coupon, item_brand, discount, index from position; itemId from product_id, quantity, unitPrice |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – remove_from_cart |
event.conversionValue | Float: Conversion value. | Expression – TOTAL_VALUE(properties) |
event.conversionCount | Integer: Conversion quantity. | properties.quantity |
event.cartData.items | Array: Cart items. | Expression – item_name, item_category, item_variant, coupon, item_brand, discount, index from position; itemId from product_id, quantity, unitPrice |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – begin_checkout |
event.conversionValue | Float: Conversion value. | properties.revenue |
event.conversionCount | Integer: Conversion quantity. | Expression – sum of product quantities |
event.cartData | Object: Cart items and event-level coupon codes. | Expression – couponCodes from properties.coupon; items map item_name, item_category; itemId from product_id, quantity, unitPrice |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – refund |
event.conversionValue | Float: Conversion value. | properties.revenue |
event.conversionCount | Integer: Conversion quantity. | Expression – sum of product quantities |
event.additionalEventParameters | Array: GA4 event parameters. | Expression – tax, shipping |
event.cartData | Object: Cart items and event-level coupon codes. | Expression – couponCodes from properties.coupon; items map item_name, item_category, index from position; itemId from product_id, quantity, unitPrice |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – view_cart |
event.conversionValue | Float: Conversion value. | Expression – TOTAL_VALUE(properties.products) |
event.conversionCount | Integer: Conversion quantity. | Expression – sum of product quantities |
event.cartData.items | Array: Cart items. | Expression – item_name, item_category; itemId from product_id, quantity, unitPrice |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – view_item |
event.conversionValue | Float: Conversion value. | Expression – TOTAL_VALUE(properties) |
event.conversionCount | Integer: Conversion quantity. | properties.quantity |
event.cartData.items | Array: Cart items. | Expression – item_name, item_category, item_variant, item_brand, coupon, discount, index from position; itemId from product_id, quantity, unitPrice |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – view_item_list |
event.additionalEventParameters | Array: GA4 event parameters. | Expression – item_list_id, item_list_name |
event.cartData.items | Array: Cart items. | Expression – item_name, item_category, index from position; itemId from product_id, quantity, unitPrice |
| Output Key | Description | Expected Input |
|---|
event.eventName Required | String: GA4 event name. | Enrichment – select_promotion |
event.additionalEventParameters | Array: GA4 event parameters. | Expression – promotion_id, promotion_name from name, creative_name from creative, creative_slot from position |
These identifiers must be mapped to Google Data Manager in order for successful user matching to occur. Without these IDs, any events sent to Google Data Manager may not be accurately reflected in reporting.
| Attribute | Example | Sync Injector Required? |
|---|
clientId Required | 1234567890.1234567890 | Yes |
gclid Recommended | Cj0KCQjw_pval | Yes |
wbraid Recommended | Cj0KCQiAr8c | Yes |
dclid Recommended | CKDdz-fE_IUDFYtTCQkdbyMOPg | Yes |
matchId Recommended | b171a9b06ce011ecafcd1b209be8601b | No |
mobileDeviceId Recommended | 38400000-8cf0-11bd-b23e-10b96e40000d | No |
email_hash Recommended | 3e693cf7e5b67880bff33b2d2626dadb7bf1d4bc737192e47cf8baa89acf2250 | No |
phone_hash Recommended | d634b0526e6b... | No |
validateOnly is set to false in the global enrichments, so the kit sends live events by default. To test without writing data, set validateOnly to true — the API validates each request and returns only errors, not results. Switch it back to false before going live.
Use RetrieveRequestStatus with the requestId from a successful ingestion response to check per-destination processing status. Google recommends waiting 30 minutes before the first check, then polling with exponential backoff up to 24 hours until status reaches SUCCESS, PARTIAL_SUCCESS, or FAILURE.