Google Data Manager API
The Google Data Manager API destination package provides server-side integration for sending conversion events and audience data to Google's advertising ecosystem through a single unified API endpoint.
Google Data Manager API is a server destination in the walkerOS flow:
Sends conversion events server-side to Google Ads, Display & Video 360, and GA4 through a single unified API.
Installation
npm install @walkeros/server-destination-datamanagerimport { startFlow } from '@walkeros/collector';
import { destinationDataManager } from '@walkeros/server-destination-datamanager';
await startFlow({
destinations: {
datamanager: {
code: destinationDataManager,
config: {
// Service account credentials
credentials: {
client_email: process.env.GOOGLE_CLIENT_EMAIL,
private_key: process.env.GOOGLE_PRIVATE_KEY,
},
settings: {
destinations: [
{
operatingAccount: {
accountId: '123-456-7890',
accountType: 'GOOGLE_ADS',
},
productDestinationId: 'AW-CONVERSION-123',
},
],
},
},
},
},
});Configuration
This destination uses the standard destination config wrapper (consent, data, env, id, ...). For the shared fields see destination configuration. Package-specific fields live under config.settings and are listed below.
Settings
| Property | Type | Description | More |
|---|---|---|---|
credentials | credentials | Service account credentials (client_email + private_key). Recommended for serverless environments. (deprecated: use config.credentials) | |
client_email | string | Service account email | |
private_key | string | Service account private key (PEM format) | |
keyFilename | string | Path to service account JSON file. For local development or environments with filesystem access. | |
scopes | Array<string> | OAuth scopes for Data Manager API. Defaults to datamanager scope. | |
destinations | Array<object> | Array of destination accounts and conversion actions/user lists (max 10) | |
eventSource | Event source for all events. Defaults to WEB. Values: WEB, APP, IN_STORE, PHONE, OTHER | ||
batchSize | integer | Maximum number of events to batch before sending (max 2000, like 100) | |
batchInterval | integer | Time in milliseconds to wait before auto-flushing batch | |
validateOnly | boolean | If true, validate request without ingestion (testing mode) | |
url | string | Override API endpoint for testing | |
consent | consent | Request-level consent for all events | |
adUserData | Consent for data collection and use | ||
adPersonalization | Consent for ad personalization | ||
testEventCode | string | Test event code for debugging | |
logLevel | Log level for debugging (debug shows all API calls) | ||
userData | Record<string, any> | Guided helper: User data mapping for all events | |
userId | any | Guided helper: First-party user ID for all events | |
clientId | any | Guided helper: GA4 client ID for all events | |
appInstanceId | any | Guided helper: GA4 app instance ID (Firebase) for all events | |
sessionAttributes | any | Guided helper: Privacy-safe attribution for all events | |
consentAdUserData | string | boolean | Consent mapping: Field name from event.consent (like 'marketing') or static boolean value | |
consentAdPersonalization | string | boolean | Consent mapping: Field name from event.consent (like 'targeting') or static boolean value |
Mapping
This package does not define custom rule-level settings. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.
Examples
Page view
A page view is sent to Data Manager as a page_view event tied to the walker user id.
{
"name": "page view",
"data": {
"title": "Pricing",
"url": "https://example.com/pricing"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"pagegroup": "docs"
},
"custom": {
"completely": "random"
},
"user": {
"id": "visitor-55"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "ev-1700000902000",
"trigger": "load",
"entity": "page",
"action": "view",
"timestamp": 1700000902000,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "express",
"platform": "server"
}
}{
"name": "page_view",
"data": {
"map": {
"transactionId": "id",
"eventName": {
"value": "page_view"
},
"userId": "user.id"
}
}
}fetch("https://datamanager.googleapis.com/v1/events:ingest", {
"method": "POST",
"headers": {
"Authorization": "Bearer ya29.c.test_token",
"Content-Type": "application/json"
},
"body": "{\"events\":[{\"eventTimestamp\":\"2023-11-14T22:28:22.000Z\",\"transactionId\":\"ev-1700000902000\",\"userId\":\"visitor-55\",\"eventName\":\"page_view\",\"eventSource\":\"WEB\"}],\"destinations\":[{\"operatingAccount\":{\"accountId\":\"123-456-7890\",\"accountType\":\"GOOGLE_ADS\"},\"productDestinationId\":\"AW-CONVERSION-123\"}],\"encoding\":\"HEX\"}"
})Lead
A demo request form submission is sent to Data Manager as a generate_lead conversion with a hashed email.
{
"name": "form submit",
"data": {
"type": "demo-request"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"email": "prospect@example.com"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "ev-1700000901000",
"trigger": "test",
"entity": "form",
"action": "submit",
"timestamp": 1700000901000,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "express",
"platform": "server"
}
}{
"name": "generate_lead",
"data": {
"map": {
"transactionId": "id",
"eventName": {
"value": "generate_lead"
},
"conversionValue": {
"value": 10
},
"currency": {
"value": "USD"
},
"email": "user.email"
}
}
}fetch("https://datamanager.googleapis.com/v1/events:ingest", {
"method": "POST",
"headers": {
"Authorization": "Bearer ya29.c.test_token",
"Content-Type": "application/json"
},
"body": "{\"events\":[{\"eventTimestamp\":\"2023-11-14T22:28:21.000Z\",\"transactionId\":\"ev-1700000901000\",\"userData\":{\"userIdentifiers\":[{\"emailAddress\":\"395ec5f334be0ab5b28568a1e7f6ed5ea80e443fb1ce3d803340586a3df46642\"}]},\"conversionValue\":10,\"currency\":\"USD\",\"eventName\":\"generate_lead\",\"eventSource\":\"WEB\"}],\"destinations\":[{\"operatingAccount\":{\"accountId\":\"123-456-7890\",\"accountType\":\"GOOGLE_ADS\"},\"productDestinationId\":\"AW-CONVERSION-123\"}],\"encoding\":\"HEX\"}"
})Purchase
A completed order is posted to Google Data Manager as a purchase conversion with hashed user identifiers.
{
"name": "order complete",
"data": {
"id": "ORD-600",
"total": 149.99,
"currency": "EUR"
},
"context": {
"shopping": [
"complete",
0
]
},
"globals": {
"pagegroup": "shop"
},
"custom": {
"completely": "random"
},
"user": {
"id": "user-abc",
"email": "buyer@example.com"
},
"nested": [
{
"entity": "product",
"data": {
"id": "ers",
"name": "Everyday Ruck Snack",
"color": "black",
"size": "l",
"price": 420
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
},
{
"entity": "product",
"data": {
"id": "cc",
"name": "Cool Cap",
"size": "one size",
"price": 42
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
},
{
"entity": "gift",
"data": {
"name": "Surprise"
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
}
],
"consent": {
"functional": true
},
"id": "ev-1700000900000",
"trigger": "load",
"entity": "order",
"action": "complete",
"timestamp": 1700000900000,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "express",
"platform": "server"
}
}{
"name": "purchase",
"data": {
"map": {
"transactionId": "data.id",
"conversionValue": "data.total",
"currency": {
"key": "data.currency",
"value": "USD"
},
"eventName": {
"value": "purchase"
},
"userId": "user.id",
"email": "user.email"
}
}
}fetch("https://datamanager.googleapis.com/v1/events:ingest", {
"method": "POST",
"headers": {
"Authorization": "Bearer ya29.c.test_token",
"Content-Type": "application/json"
},
"body": "{\"events\":[{\"eventTimestamp\":\"2023-11-14T22:28:20.000Z\",\"transactionId\":\"ORD-600\",\"userId\":\"user-abc\",\"userData\":{\"userIdentifiers\":[{\"emailAddress\":\"6a6c26195c3682faa816966af789717c3bfa834eee6c599d667d2b3429c27cfd\"}]},\"conversionValue\":149.99,\"currency\":\"EUR\",\"eventName\":\"purchase\",\"eventSource\":\"WEB\"}],\"destinations\":[{\"operatingAccount\":{\"accountId\":\"123-456-7890\",\"accountType\":\"GOOGLE_ADS\"},\"productDestinationId\":\"AW-CONVERSION-123\"}],\"encoding\":\"HEX\"}"
})Guided mapping helpers
Define common fields once in Settings instead of repeating them in every event mapping:
await startFlow({
destinations: {
datamanager: {
code: destinationDataManager,
config: {
credentials: { /* ... */ },
settings: {
destinations: [...],
// Guided helpers (apply to all events)
userData: {
email: 'user.mail',
phone: 'data.phone',
},
userId: 'user.id',
clientId: 'user.device', // GA4 web stream
appInstanceId: 'user.appInstanceId', // GA4 app stream (Firebase)
sessionAttributes: 'context.sessionAttributes',
// Consent mapping
consentAdUserData: 'marketing',
consentAdPersonalization: 'personalization',
},
},
},
},
});Consent mapping: Map your consent field names (string) or use static values (boolean). Event mappings always override Settings helpers.
Store sales (IN_STORE)
For physical store conversions, set eventSource: 'IN_STORE' on the destination
and map a storeId in the event mapping. The destination wraps it into the
API's required eventLocation.storeId shape.
mapping: {
order: {
complete: {
name: 'purchase',
data: {
map: {
transactionId: 'data.id',
conversionValue: 'data.total',
currency: 'data.currency',
storeId: 'data.storeId',
email: 'user.email', // hashed PII still applies
},
},
},
},
}Hash encoding
Every request is sent with encoding: 'HEX'. Google requires the field
whenever the payload contains hashed userData. The value is pinned because
all hashing in this destination produces lowercase hex SHA-256 digests;
exposing encoding as a setting would risk silently mismatched identifiers.