Google Ads ExecModule
Overview
GoogleAdsModule connects ValkyrAI workflows to Google Ads API v25 through the native map I/O ExecModule ABI. It discovers directly accessible accounts, traverses manager-account clients, retrieves campaigns, reports campaign performance, inspects ad groups and keywords, and runs guarded Google Ads Query Language (GAQL) reads without exposing credentials to workflow data.
The connector uses only googleads.googleapis.com. Every exposed operation is read-only, including the provider's POST .../googleAds:search route, so transient failures may receive bounded retries. The module does not create or change campaigns, budgets, bids, ads, assets, audiences, conversions, account links, billing, or user access.
Usage
- Enable the Google Ads API in the Google Cloud project that owns the OAuth client.
- Authorize a dedicated Google principal with
https://www.googleapis.com/auth/adwordsand access to the required Ads accounts. - Apply for an appropriate Google Ads developer-token access level and store the approved token separately from the OAuth access token.
- Store the OAuth access token in the encrypted
IntegrationAccount.apiKeySecureField, the developer token in encryptedIntegrationAccount.password, and the default ten-digit target customer ID inIntegrationAccount.accountId. - Set the IntegrationAccount to
READYand bind it throughExecModuleConfig.authConfig.integrationAccount. - Run
list_accessible_customersfirst. When operating through a manager account, pass its ten-digit ID asloginCustomerIdand the client account ascustomerId. - Use a predefined operation for common reports; reserve
searchfor a bounded, reviewed GAQLSELECT.
Workflow input cannot provide authorization or developer-token headers, an arbitrary API host, OAuth client secrets, refresh tokens, mutation endpoints, comments, semicolon-separated GAQL, or non-SELECT statements.
Inputs
| Name | Type | Requirement | Default | Description and constraints |
|---|---|---|---|---|
operation | string | Required | None | One of the eight documented operations. |
customerId | string | All operations except list_accessible_customers | IntegrationAccount.accountId | Exactly ten digits after optional display hyphens are removed. |
loginCustomerId | string | Manager-mediated access only | None | Optional ten-digit manager account ID sent as login-customer-id; ignored for accessible-account discovery. |
campaignId | string | get_campaign | None | Positive numeric campaign ID, up to 20 digits. |
status | string | Optional list/report filter | None | ENABLED, PAUSED, or REMOVED. |
dateFrom / dateTo | ISO date | campaign_performance | None | Inclusive range; dateTo must not precede dateFrom, and the range is capped at 367 days. |
query | string | search | None | One GAQL SELECT ... FROM ... statement, at most 64 KiB, without comments or semicolons. |
limit | integer | Optional | 1000 | Maximum normalized rows across pages, 1–20,000. Built-in GAQL also carries the same provider-side LIMIT. |
pageToken | string | Optional | None | Opaque continuation token, at most 4,096 non-whitespace characters. Reuse only with the identical customer and GAQL query. |
maxPages | integer | Optional | 3 | Maximum fixed-size Google Ads pages followed in one execution, 1–10. |
maxAttempts | integer | Optional | 3 | Maximum attempts per logically read-only HTTP request, 1–10. |
timeoutMs | integer | Optional | 30000 | HTTP timeout, 100–300,000 ms. |
Outputs
| Name | Type | When present | Description |
|---|---|---|---|
status | string | Always | success or error. |
operation | string | Always | Normalized operation. |
httpStatus / attempts | integer | Provider request | Final HTTP status and total HTTP attempts consumed. |
items / count | array / integer | Success | Accessible-account objects or provider-shaped Google Ads result rows and their count. |
pages | integer | GAQL operation | Provider result pages consumed. |
nextPageToken | string | More rows remain | Opaque continuation token when limit or maxPages stopped traversal. |
requestIds | array | Provider returned IDs | Google support diagnostics from response headers; these are not credentials. |
error | object | Failure | Safe {code,message,httpStatus?,retryable} details. |
OAuth tokens, developer tokens, authorization values, and secret-bearing provider messages are redacted from errors, logs, outputs, and workflow events.
IntegrationAccount Requirements
| Setting | Requirement |
|---|---|
| Provider | Google OAuth principal with Google Ads API access |
accountName | Human-readable automation identity |
accountId | Default ten-digit target Ads customer ID, for example 1234567890 |
apiKey | Encrypted SecureField containing a short-lived OAuth access token |
password | Encrypted SecureField containing the Google Ads developer token |
| OAuth scope | https://www.googleapis.com/auth/adwords |
status | Exactly READY |
Grant access only to the required advertiser or manager hierarchy. OAuth issuance, refresh, rotation, revocation, developer-token approval, and access-level changes remain IntegrationAccount lifecycle responsibilities. A developer token identifies the calling application but does not replace the user's OAuth authorization.
Configuration
{
"version": "1.0.0",
"authConfig": {
"authStrategy": 1,
"integrationAccount": "integration-account:google-ads-production"
},
"retryPolicy": {
"maxAttempts": 3,
"backoffStrategy": "EXPONENTIAL",
"initialDelayMs": 1000,
"maxDelayMs": 60000
},
"payloadConfig": {
"parameters": "{\"operation\":\"campaign_performance\",\"loginCustomerId\":\"1112223333\",\"limit\":1000,\"maxPages\":3}"
}
}
The integration-account reference is symbolic. Persisted workflows use the generated relationship and never plaintext OAuth or developer tokens.
Operations
| Operation | Google Ads behavior | Side effect |
|---|---|---|
list_accessible_customers | Calls customers:listAccessibleCustomers and normalizes each resource name plus customer ID. | Read-only. |
list_customer_clients | Queries client accounts visible beneath a manager, including name, currency, time zone, manager flag, level, and status. | Read-only. |
get_campaign | Retrieves one campaign and its budget summary by numeric campaign ID. | Read-only. |
list_campaigns | Lists campaigns with identity, status, channel, schedule, optimization score, and budget fields. | Read-only. |
campaign_performance | Reports daily campaign impressions, clicks, interactions, cost, conversions, conversion value, cost per conversion, and click-through rate. | Read-only. |
list_ad_groups | Lists ad groups with campaign identity and bounded delivery metrics. | Read-only. |
list_keywords | Lists keyword criteria, match types, statuses, campaign/ad-group identity, and bounded delivery metrics. | Read-only. |
search | Runs one validated GAQL SELECT against the target customer. | Read-only. |
Errors and Failure Modes
| Code | Typical cause | Retryable | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Missing/invalid ID, date, status, continuation token, credential, or GAQL statement. | No | Correct the named input; no provider request was sent. |
UNSUPPORTED_OPERATION | Unknown operation. | No | Select a documented operation. |
INTEGRATION_ACCOUNT_REQUIRED | No bound account. | No | Bind a Google Ads IntegrationAccount. |
INTEGRATION_ACCOUNT_NOT_READY | Account is not READY. | No | Repair or reconnect the account. |
GOOGLE_ADS_UNAUTHENTICATED / GOOGLE_ADS_HTTP_401 | Expired, revoked, or invalid OAuth access token. | No | Refresh the IntegrationAccount OAuth token. |
GOOGLE_ADS_PERMISSION_DENIED / GOOGLE_ADS_HTTP_403 | Missing scope, account access, developer-token level, or manager relationship. | No | Grant only the missing authority and confirm customer hierarchy. |
GOOGLE_ADS_NOT_FOUND / GOOGLE_ADS_HTTP_404 | Customer or resource is wrong or unavailable to the principal. | No | Verify IDs and the manager/client relationship. |
GOOGLE_ADS_INVALID_ARGUMENT / GOOGLE_ADS_HTTP_400 | Google rejected a GAQL field, combination, date, resource, or version-specific contract. | No | Correct the query using v25 field metadata. |
GOOGLE_ADS_RESOURCE_EXHAUSTED / GOOGLE_ADS_HTTP_429 | Daily operations or short-window quota is exhausted. | Yes | Honor Retry-After, reduce concurrency, and inspect the developer-token access level. |
GOOGLE_ADS_HTTP_5xx | Transient provider failure. | Yes | Retry with bounded backoff. |
NETWORK_ERROR | Timeout, DNS, TLS, or connectivity failure. | Yes | Verify connectivity and retry later. |
RESPONSE_TOO_LARGE | One provider page exceeded 10 MiB. | No | Narrow fields or filters, lower the GAQL limit, or split the date range. |
Example
Report enabled-campaign performance for ten days:
{
"operation": "campaign_performance",
"customerId": "1234567890",
"loginCustomerId": "1112223333",
"dateFrom": "2026-08-01",
"dateTo": "2026-08-10",
"status": "ENABLED",
"limit": 1000,
"maxPages": 3
}
Expected result:
{
"status": "success",
"operation": "campaign_performance",
"httpStatus": 200,
"count": 1,
"pages": 1,
"items": [
{
"campaign": {
"id": "42",
"name": "Enterprise AI",
"status": "ENABLED"
},
"segments": {"date": "2026-08-10"},
"metrics": {
"impressions": "1300",
"clicks": "62",
"costMicros": "175000000",
"conversions": 9.0,
"conversionsValue": 4200.0
}
}
],
"requestIds": ["provider-request-id"],
"attempts": 1
}
Notes
- Pagination: Google Ads
Searchreturns fixed-size pages of up to 10,000 rows. The deprecatedpageSizefield is deliberately never sent. The connector followsnextPageTokenup tomaxPagesandlimit, then returns the remaining token. Continuations must keep the customer and GAQL query identical. - Rate limits: every exposed operation is logically read-only, even though GAQL search uses HTTP
POST. HTTP 408, 429, 500, 502, 503, and 504 and network failures may retry up tomaxAttempts, honoring numeric or RFC-1123Retry-Afterand bounded exponential backoff. Google Ads operations still count against the developer token's access-level quota. - API limits: GAQL/request bodies are capped at 64 KiB, responses at 10 MiB per page, normalized output at 20,000 rows, traversal at 10 pages, and performance ranges at 367 inclusive days. Built-in list/report queries include a provider-side
LIMIT. - Idempotency: all exposed operations are reads and introduce no provider-side mutation. Results may change as ads deliver, attribution settles, account access changes, or Google refreshes metrics.
- Destructive behavior: none is exposed. Campaign/ad/budget mutation, status changes, billing, access management, conversion uploads, audience management, and resource removal are intentionally deferred.
- Privacy: Ads output can contain confidential spend, conversion, audience, and performance data. Keep downstream workflows inside the same authorization boundary and apply contractual, consent, retention, and data-minimization requirements.
- Manager accounts:
loginCustomerIdidentifies the authorized manager used to reachcustomerId.list_accessible_customersintentionally omits that header because Google ignores it for account discovery. - Custom GAQL: local validation proves that
searchis one comment-freeSELECT, but Google remains authoritative for fields, resources, compatibility, enum values, and API-version behavior. - External verification: local tests cover fixed-host routing, OAuth/developer/manager headers, account discovery, predefined GAQL, date/ID/status validation, continuation pagination, read-only retry, request IDs, redaction, credential failures, and metadata discovery. Live account hierarchy, token approval level, quota, OAuth refresh, campaign values, and Google Ads policy compliance require separately authorized Google Ads credentials and are not exercised in repository tests.
- Functional references: n8n Google Ads node source, Google Ads REST authentication, Search and SearchStream, and list accessible accounts.