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. Support for PII-only conversions (hashed user data with no click or device ID) varies by destination:
- Google Ads: accepts
gclid, gbraid, wbraid, or userData — PII-only conversions are always supported.
- GA4: PII-only is supported only in multi-source mode (events sent with a
transactionId as an additional data source to an allowlisted property), where clientId, userId, or userData alone is sufficient. Outside multi-source mode, GA4 requires clientId (or appInstanceId) as its primary identifier.
- Floodlight: PII-only is never sufficient, in either mode — it always requires at least one of
gclid, dclid, matchId, impressionId, mobileDeviceId, or encryptedUserIds, and rejects 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 you do not use a given platform, that entry must be removed from the destinations Lua, the matching reference must be removed from event.destinationReferences in each event, and any event left with no remaining destination should be deleted entirely. Any now-unneeded conditions should also be removed from the filters section.
- 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 — note that leaving the array empty sends the event to all remaining destinations, so decide whether that is the intended behavior; if not, delete the event itself. If the removed destination was the last one for its platform, also remove any now-unneeded conditions from the filters section.
- 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 returns an error.
- 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.
- Using
cartData requires a Google Merchant Center account with a product feed. The merchantProductId values must match the item IDs in that feed exactly, or the match fails even when the field is populated.
- The kit sets
event.consent.adUserData and event.consent.adPersonalization to CONSENT_GRANTED statically; confirm this matches the pipeline's consent enforcement.
- There is no processing delay recommended for Google Ads conversions. For Floodlight conversions, it is recommended to allow approximately two hours for a newly created ad identifier to process before it is used to match a conversion. Please reach out to your MetaRouter representative to set up a delay.
- 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.
Multi-Source Conversions is a Google Ads configuration, currently in beta, that lets one conversion action accept data from both the Google tag and a server-side feed. Google matches the two on transaction ID, deduplicates them, and fills in conversions the tag missed. Google's Help Center calls this "conversions with multiple data sources".
MSC is not a MetaRouter integration — it is configuration in your Google Ads account. The server-side feed it consumes is delivered through the Google Data Manager — Events integration. MSC is independent of Google Tag Gateway and works with or without it.
No MSC-specific field or flag is required in the payload. A matching transaction ID plus conversion date and time is sufficient for automatic deduplication. An MSC-ready configuration requires:
- A Google Data Manager — Events integration configured against your Google Ads destination, targeting the specific conversion action that has the additional data source connected.
- A transaction ID on the event. This originates from your own conversion event — your order ID — rather than from the sync injector, which carries and maps it. The same ID must also be present on your client-side Google tag conversion, or there is nothing to match against.
- Conversion date and time on each delivered conversion.
- Conversion value and currency. Required for Google to reconcile value, and required to see any reported uplift.
- MSC enablement on your Google Ads account, requested through your Google representative. It is a beta and not self-serve.
- Allowlisting to connect an additional data source via the Data Manager API.
- A website conversion action created manually via the Google tag or Google Tag Manager. Imported Google Analytics conversions and URL-based conversion actions are not eligible.
- A conversion event that reliably generates and sends a consistent transaction ID.
- The server-side feed becomes the source of truth for conversion value. When a transaction ID matches an existing tag event, the uploaded value overwrites the value the tag recorded.
- Deduplication is scoped to a single conversion action. It does not deduplicate across other conversion actions in the account. If a new conversion action is created for this purpose, it must not sit alongside the original in the same campaign goal set, or conversions will be double-counted.
- A newly connected data source enters a 14-day trial period during which its data is used for reporting and diagnostics but does not affect bidding. After the trial it becomes biddable automatically, regardless of outstanding diagnostic alerts.
- Google raises an urgent diagnostic if transaction ID overlap between the two sources falls below 10%.
- Conversions still require a click identifier to be counted. Deduplication does not depend on GCLID, but a conversion with no associated click will not increment the reported conversion count. This is expected behaviour, not a delivery failure.
- 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, which the integration reads server-side under
context.providers.googleAnalytics4.clientID.
- The CM360 child sync captures
gclid and dclid; the Google Ads child sync captures wbraid. All three fall back to context.providers.googleGtag.data when the specific child sync is not configured.
matchId is not sync-dependent — it is mapped from MetaRouter's anonymousId and used as a fallback identifier when no click ID is available.
- 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. Alternatively, you can check each platform's dashboard.