IntegrationsAdvertisingGoogle Ads Conversions

Google Ads Conversions

Datafly Signal delivers offline and enhanced conversions to Google Ads server-to-server via the Google Ads API (ConversionUploadService). This replaces client-side conversion tags with direct server uploads, improving measurement accuracy and enabling conversion-based bidding optimisation without relying on browser-side scripts.

⚠️

Delivery status. The Google Ads delivery currently targets Google Ads API v17, which Google has sunset, so uploads are rejected until the delivery moves to a supported version (#1127). Since 15 June 2026 Google also refuses uploadClickConversions from projects new to offline conversion import; new adopters should use the Google Data Manager integration. The blueprint below is correct for the upload format.

Why route Google Ads through Datafly Signal

  • Conversions survive ad blockers and tracking prevention. A browser tag served from an advertising domain is blocked outright for part of your traffic, and Safari’s ITP shortens the cookies it can set. Signal sends the event from your own server, so the conversions Google Ads optimises against are not filtered by the browser.
  • Email, phone number, first name and last name are hashed before leaving your infrastructure. Signal normalises (trim and lowercase) and applies SHA-256 inside your own deployment, so Google Ads receives match keys rather than raw personal data.
  • Click identifiers are captured and replayed. Signal stores gbraid, gclid, wbraid first-party at collection time and attaches them to the conversion later, so attribution survives even when the original landing cookie has expired.
  • Delivery is batched, rate-limited, and retried. Signal buffers to Kafka, respects the Google Ads rate limit, and retries on 429 or transient failure rather than dropping the event.
  • Token lifecycle is handled for you. Signal obtains and refreshes the OAuth credentials Google Ads requires, so nothing expires quietly in the middle of a campaign.
  • Presets for Retail, B2B / SaaS and Automotive. The mapping starts from a working configuration for your vertical instead of a blank field map.
  • One consent decision governs every destination. Google Ads is gated by the same consent state as the rest of your stack, so a withdrawal applies everywhere at once.
  • No vendor tag on the page. Removing it removes its page weight and its independent access to your visitors.

Prerequisites

Setting up Google Ads for server-side conversion tracking requires a Google Ads account, a conversion action, OAuth2 credentials, and (optionally) Enhanced Conversions enabled. Follow each step below before configuring the integration in Signal.

You need an active Google Ads account. If you manage multiple accounts through a Manager Account (MCC), you can use either the MCC customer ID or the individual account’s customer ID.

  1. Sign in to Google Ads.
  2. Your Customer ID is displayed in the top-right corner of the dashboard, formatted as 123-456-7890.
  3. Note this value — you will need it when configuring the integration in Signal.

When entering the Customer ID in Signal, you can use either the dashed format (123-456-7890) or the plain numeric format (1234567890). Signal accepts both.

Create a Conversion Action

A conversion action tells Google Ads what type of conversion you are tracking and how to count it.

  1. In Google Ads, navigate to Tools & Settings > Measurement > Conversions.
  2. Click + New Conversion Action.
  3. Select Import as the conversion source.
  4. Choose Other data sources or CRMs > Track conversions from clicks.
  5. Name the conversion action (e.g. “Website Purchase”, “Lead Form Submit”).
  6. Set the Category (e.g. Purchase, Lead, Sign-up), Value, and Count (one per click or every).
  7. Click Create and Continue.
  8. After creation, find the Conversion Action ID — this is a numeric ID visible in the conversion action’s details page URL or under the tag setup instructions.
⚠️

The Conversion Action ID is a numeric value (e.g. 987654321), not the conversion action name. You can find it in the URL when viewing the conversion action: ...&ctId=987654321.

Enable Enhanced Conversions

Enhanced Conversions allow Google to match server-uploaded conversions to signed-in Google users using hashed first-party data (email, phone, address). This significantly improves attribution when gclid is not available.

  1. In Google Ads, go to Tools & Settings > Measurement > Conversions.
  2. Click on the conversion action you created.
  3. Expand the Enhanced conversions section.
  4. Toggle Enhanced conversions on.
  5. Select Google Ads API as the method for sending enhanced conversion data.
  6. Accept the customer data terms.
  7. Click Save.

Enhanced Conversions are optional but strongly recommended. Without them, conversions can only be attributed via click identifiers (gclid, wbraid, gbraid). With Enhanced Conversions enabled, Signal automatically hashes and sends user data alongside the conversion for improved match rates.

Set Up OAuth2 Credentials

Google Ads API requires OAuth2 authentication. You need to create credentials in Google Cloud Console and generate a refresh token.

Create OAuth Client Credentials:

  1. Go to Google Cloud Console.
  2. Create a new project or select an existing one.
  3. Navigate to APIs & Services > Library.
  4. Search for Google Ads API and click Enable.
  5. Go to APIs & Services > Credentials.
  6. Click Create Credentials > OAuth Client ID.
  7. If prompted, configure the OAuth consent screen first (External or Internal depending on your organisation).
  8. Select Web application as the application type.
  9. Under Authorized redirect URIs, add: https://developers.google.com/oauthplayground
  10. Click Create.
  11. Note the Client ID and Client Secret from the confirmation dialog.

Generate a Refresh Token

The refresh token gives Signal ongoing access to your Google Ads account without requiring repeated sign-in.

  1. Go to the OAuth 2.0 Playground.
  2. Click the gear icon (Settings) in the top-right corner.
  3. Check Use your own OAuth credentials.
  4. Enter your Client ID and Client Secret from the previous step.
  5. Close the settings panel.
  6. In the left panel under Step 1, find and expand Google Ads API (or manually enter the scope: https://www.googleapis.com/auth/adwords).
  7. Select the https://www.googleapis.com/auth/adwords scope.
  8. Click Authorize APIs.
  9. Sign in with a Google account that has admin access to the Google Ads account you want to track conversions for.
  10. Grant the requested permissions.
  11. Back in the Playground, under Step 2, click Exchange authorization code for tokens.
  12. Copy the Refresh Token from the response.
⚠️

Store your OAuth credentials securely. The refresh token provides ongoing access to your Google Ads account and does not expire unless explicitly revoked. If compromised, revoke it immediately in Google Cloud Console > Credentials.

If you manage multiple Google Ads accounts through a Manager Account (MCC) and want to upload conversions to a child account:

  1. In your MCC dashboard, go to Tools & Settings > Setup > Linked accounts.
  2. Ensure the target account is linked and the link is accepted.
  3. Use the MCC Customer ID as the customer_id in Signal, and the conversion action from the child account.

When using an MCC, the OAuth credentials must be for a user with access to the MCC. Signal will use the MCC customer ID to authenticate and upload conversions to the linked child account.

Configuration

FieldRequiredTypeDescription
customer_idYesstringYour Google Ads customer ID (digits only, no dashes). Templated into the upload endpoint URL. Found top-right in the Google Ads console.
developer_tokenYessecretYour Google Ads API developer token (API Center under the manager/MCC account). Sent as the developer-token request header; the API rejects all calls without it.
conversion_action_idYesstringThe numeric ID of the conversion action in Google Ads (Tools > Conversions). Used to build the conversion_action resource name customers/{customer_id}/conversionActions/{conversion_action_id}.
client_idYesstringOAuth2 client ID from the Google Cloud project authorised for the Google Ads API. Sent in the refresh_token grant when minting access tokens.
client_secretYessecretOAuth2 client secret paired with the client ID. Required by Google’s token endpoint for the refresh_token grant.
refresh_tokenYessecretLong-lived OAuth2 refresh token for the authorised Google Ads user, with the https://www.googleapis.com/auth/adwords scope. Exchanged for short-lived access tokens at delivery time.

Configure in Signal

Management UI Setup

  1. Go to Integrations > Add Integration > Google Ads Conversions and choose a preset.
  2. Enter your Customer ID (digits only, no dashes) and Conversion Action ID.
  3. Enter the OAuth Client ID, Client Secret and Refresh Token, and the Developer Token.
  4. Select consent categories (typically advertising).
  5. Click Save.

Management API Setup

curl -X POST http://localhost:8084/v1/admin/integration-catalog/google_ads/install \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Google Ads - Purchases",
    "preset": "ecommerce",
    "config": {
      "customer_id": "1234567890",
      "conversion_action_id": "987654321",
      "developer_token": "YOUR_DEVELOPER_TOKEN",
      "client_id": "123456789-abcdefg.apps.googleusercontent.com",
      "client_secret": "GOCSPX-abcdefghijklmnop",
      "refresh_token": "1//0abcdefghijklmnopqrstuvwxyz"
    }
  }'

Presets

PresetConversions it uploads
Retail (ecommerce)Purchases (order ID, value, currency), add-to-cart and checkout.
B2B / SaaS (saas)Sign-ups, leads and paid subscriptions.
AutomotiveFinance quotes, trade-in valuations, test drives, service bookings, dealer enquiries and brochure downloads.
InsurancePolicy sales (purchase, policy_purchased) with the policy number as order ID and the premium as value.

One integration uploads to one conversion action (conversion_action_id). To report leads and sales to different conversion actions, add one integration per conversion action and keep the events each should send (see Multiple conversion actions).

Identity signals

SignalFieldNotes
Google click IDgclidFrom the landing page URL. Exactly one click ID is sent per conversion: gclid, else gbraid, else wbraid.
App-to-web click IDgbraidSent only when there is no gclid.
Web-to-app click IDwbraidSent only when there is neither gclid nor gbraid.
Emailuser_identifiers[].hashed_emailNormalised SHA-256 (trimmed, lower-cased).
Phoneuser_identifiers[].hashed_phone_numberNormalised SHA-256 of the E.164 number.

Google accepts only email and phone as user identifiers on click conversion uploads, so names and addresses are not sent. Google only matches on these values, so they are never sent in plain text. See Personal data by integration.

API endpoint

POST https://googleads.googleapis.com/v17/customers/{{customer_id}}:uploadClickConversions

Allow egress to googleads.googleapis.com from the network your delivery workers run on.

Presets and event mapping

Every conversion carries conversion_action (customers/<customer_id>/conversionActions/<conversion_action_id>, from the integration settings), conversion_date_time (yyyy-mm-dd hh:mm:ss+00:00), one click ID, the hashed user identifiers and consent.ad_user_data. order_id is transaction_id, else the legacy order_id; on automotive leads it is the event’s own ID, because Google deduplicates conversions on it and a vehicle or dealer ID would merge different people’s test drives into one. conversion_value is value (including tax and shipping, as the event specs define it), else the legacy revenue; currency_code is upper-cased. The event names in the tables are the Google Ads conversion categories the preset is written for; they are not sent.

Retail preset (ecommerce)

Purchases (order ID, value and currency), add-to-cart and checkout conversions with enhanced conversions data.

Signal eventGoogle Ads category eventFields the preset sets
add_to_cartADD_TO_CARTconversion_value, currency_code.
begin_checkoutBEGIN_CHECKOUTconversion_value, currency_code.
purchasePURCHASEorder_id, conversion_value, currency_code. Sent only when properties.currency is set.

B2B / SaaS preset (saas)

Sign-up, lead and paid-subscription conversions with enhanced conversions.

Signal eventGoogle Ads category eventFields the preset sets
sign_upSIGNUPconversion_value, currency_code.
generate_leadSUBMIT_LEAD_FORMconversion_value, currency_code.
subscription_startedSUBSCRIBE_PAIDorder_id, conversion_value, currency_code. Sent only when properties.currency is set.

Automotive preset (automotive)

Vehicle marketing conversions: finance quotes and trade-in valuations, test drives and service bookings, dealer enquiries and brochure downloads; order_id is the event’s own ID (Google’s per-conversion dedup key), never the vehicle or dealer ID.

Signal eventGoogle Ads category eventFields the preset sets
brochure_downloadedDOWNLOADorder_id.
finance_quote_requestedREQUEST_QUOTEconversion_value, currency_code, order_id.
trade_in_valuedREQUEST_QUOTEconversion_value, currency_code, order_id.
test_drive_bookedBOOK_APPOINTMENTorder_id.
dealer_contactedCONTACTorder_id.
service_appointment_bookedBOOK_APPOINTMENTorder_id, conversion_value, currency_code.

Insurance preset (insurance)

Policy sales as a Google Ads offline click conversion (Bennetts): purchase and policy_purchased with the policy number as order_id, the premium as conversion_value and the currency, sent only for a click (gclid, else gbraid, else wbraid) with email and phone as normalised SHA-256 hashes. One integration uploads to one conversion action: send quote leads through a second Google Ads integration with its own conversion action (lead_gen events).

Signal eventGoogle Ads category eventFields the preset sets
purchasePURCHASEorder_id, conversion_value, currency_code. Sent only when properties.currency is set.
policy_purchasedPURCHASEorder_id, conversion_value, currency_code. Sent only when properties.currency is set.

Example: purchase

A Retail purchase from a known visitor after a Google Ads click (the request body; developer-token and the OAuth access token travel as headers):

{
  "conversions": [
    {
      "consent": {
        "ad_user_data": "GRANTED"
      },
      "conversion_action": "customers/SNT-cfg-customer_id/conversionActions/SNT-cfg-conversion_action_id",
      "conversion_date_time": "2026-09-23 09:30:00+00:00",
      "conversion_value": 49995,
      "currency_code": "GBP",
      "gclid": "g-123",
      "order_id": "ORD-10042",
      "user_identifiers": [
        {
          "hashed_email": "86e0b9e56c17cc4d12387e1949b85053fbe73bc3ce5a1188713a9d300cc6133d",
          "hashed_phone_number": "a8acc3a90a7b4e4dc65e93db9240ed26523050ef754d63b75b5161de76781436"
        }
      ]
    }
  ]
}

Multiple conversion actions

Add one Google Ads integration per conversion action, each with its own conversion_action_id, and keep only the events that belong to that action in the installed blueprint (for example, one integration for purchase and one for generate_lead).

Enhanced Conversions

Enhanced conversions add the hashed email and phone to the click conversion so Google can match it to a signed-in user when the click ID alone is not enough. Call datafly.identify() when a visitor gives you their details:

datafly.identify("user-123", { email: "jane@example.com", phone: "+44 20 7946 0000" });
datafly.track("purchase", { transaction_id: "ORD-001", value: 89.99, currency: "GBP", items: [...] });

Signal trims and lower-cases the email, shapes the phone to E.164 and hashes both with SHA-256 inside your deployment before the upload.

Google asks for the visitor’s consent to use their data for advertising on every click conversion from the EEA and UK. Signal sends consent.ad_user_data: GRANTED when the visitor’s canonical marketing consent is granted, DENIED when it is refused. ad_personalization is not sent: Google accepts it only on customer match and store sales uploads, not on click conversions.

Testing

After configuring the integration, verify that conversions are arriving in Google Ads:

  1. Trigger a test conversion on your site (e.g. complete a test purchase or submit a lead form).
  2. In Google Ads, navigate to Tools & Settings > Measurement > Conversions.
  3. Click on your conversion action.
  4. Check the Diagnostics tab — recent uploads should appear within a few hours.
  5. Conversion source should display as “Uploaded (from API)” or “Website (Enhanced conversions from API)”.
  6. In the All conversions column, you should see the uploaded conversion count increase.

Google Ads may take up to 24 hours to process and display uploaded conversions. For real-time verification, check the Signal Management UI delivery logs to confirm that the API call returned a success response.

To validate in the Management UI:

  1. Go to Integrations and select your Google Ads integration.
  2. Check the Delivery Log for recent events.
  3. A 200 response code with partial_failure_error as empty confirms successful delivery.

Troubleshooting

ProblemCauseSolution
AUTHENTICATION_ERRORInvalid or expired OAuth credentials.Regenerate the refresh token using the OAuth Playground (Step 5 above) and update the credentials in Signal.
AUTHORIZATION_ERRORThe authenticated user does not have access to the Google Ads account.Ensure the Google account used in the OAuth flow has admin access to the target Google Ads account.
CUSTOMER_NOT_FOUNDIncorrect customer ID.Verify the customer ID matches the account in Google Ads. If using MCC, ensure the child account is linked.
CONVERSION_ACTION_NOT_FOUNDIncorrect conversion action ID, or the action was deleted.Check the conversion action exists in Google Ads under Tools > Conversions. Use the numeric ID, not the name.
CLICK_NOT_FOUNDThe gclid is invalid or expired (>90 days).Ensure gclid values are captured correctly. Google Click IDs expire after 90 days.
Conversions not appearingReporting delay.Google Ads can take up to 24 hours to display uploaded conversions. Check Signal delivery logs for API success.
TOO_MANY_CONVERSIONS_IN_REQUESTBatch size exceeds Google’s limit.Signal handles batching automatically. If this persists, contact support.
DUPLICATE_CONVERSIONSame order_id or gclid + timestamp combination sent twice.This is expected behaviour if events are retried. Google deduplicates on order_id.
Enhanced conversions not matchingUser identifiers not provided or incorrectly formatted.Ensure datafly.identify() is called before the conversion event with at least an email or phone number.

Rate Limits

SettingDefault
rate_limit_rps50
rate_limit_burst100

Google Ads API has per-account rate limits that vary by account tier. The defaults above are conservative. If you have a high-volume account with elevated API quotas, you can increase these values in the integration’s advanced settings.

Signal automatically batches conversion uploads and handles retries with exponential backoff. If rate limits are hit, events are queued and retried without data loss.