Skip to main content
GUIDE · GOOGLE ADS EC

Google Ads Enhanced Conversions: the 2026 setup manual

Google Ads attribution is no longer just a browser tag problem. Checkout pages, consent banners, iOS click identifiers, CRM lead stages, subscription renewals, and server-side order systems all affect whether Google can connect a paid click to the conversion that followed. Enhanced Conversions gives Google better first-party signals, but the setup has to be deliberate: normalize identifiers, preserve click IDs, upload to the correct customer account, and carry consent state into every conversion.

This manual covers the implementation path most technical marketers and ecommerce engineers need in 2026: how Enhanced Conversions differs from conversion imports, which prerequisites must be in place, how the upload payload is shaped, what consent fields mean, and how to read diagnostics after the first events arrive.

12 min read·Updated 2026-04-23
Modes

Enhanced Conversions vs Conversion Import

Google uses similar language for two related but different jobs. Enhanced Conversions for web improves an existing online conversion by attaching hashed first-party data to the event. A browser tag, Google tag, or GTM setup records the conversion with a click identifier and order ID; the enhanced signal helps Google match that conversion to signed-in users when browser identifiers are incomplete. This mode fits standard ecommerce purchases, lead forms, bookings, and checkout flows where the final conversion happens on the website and the page can still run Google instrumentation.

Conversion Import is the server-side path. Your backend, CRM, subscription platform, or tracking pipeline uploads conversions through the Google Ads API. It applies when the true conversion happens after the page view: qualified leads, offline sales, delayed payment capture, call center deals, renewals, or orders created by a backend job. In practice, mature teams often use both modes. The web page tag captures the immediate checkout conversion, while the server-side upload handles events that happen after checkout or need stronger backend governance.

The decision is not ideological. If the page reliably knows the conversion, value, order ID, and consent state, the web tag mode is simple and fast. If the server is the source of truth, use uploads. If both can see the same conversion, define ownership carefully so Google does not receive duplicate unrelated events.

Prep

Prerequisites

Most failed Google Ads Enhanced Conversions projects do not fail because the payload is complex. They fail because account access, conversion action ownership, OAuth scopes, consent, or click ID capture were assumed instead of verified. Confirm the following before writing production upload code.

Google Ads MCC or standalone account access with permission to view conversion actions and link API credentials.
Conversion actions created in Google Ads before upload testing starts, with the right category, counting method, and value settings.
Approved Google Ads developer token available in the same manager hierarchy as the target customer account.
OAuth refresh token generated for a Google user that can access the customer ID you plan to upload into.
GCLID, GBRAID, or WBRAID reliably captured from landing pages, persisted through checkout, and attached to the final order or lead record.
Runbook

Step-by-step setup

Build the integration in layers. First prove authorization. Then prove the conversion action resource. Then send a minimal click-ID conversion. Only after that should you add enhanced identifiers, fallback logic, batching, retries, and monitoring.

Step 01

Create the OAuth client and capture a refresh token

Google Ads API uploads use OAuth, not a static account key. Create an OAuth client in Google Cloud, request the Ads scope, complete the consent screen with the Google user that owns or manages the Ads account, and store the refresh token in your secrets manager. Treat the token as production infrastructure because failed refreshes stop conversion uploads silently until monitoring catches them.

GET https://accounts.google.com/o/oauth2/v2/auth
  ?client_id=GOOGLE_CLIENT_ID
  &redirect_uri=https://app.example.com/oauth/google/callback
  &response_type=code
  &scope=https://www.googleapis.com/auth/adwords
  &access_type=offline
  &prompt=consent

POST https://oauth2.googleapis.com/token
content-type: application/x-www-form-urlencoded

code=AUTH_CODE&
client_id=GOOGLE_CLIENT_ID&
client_secret=GOOGLE_CLIENT_SECRET&
redirect_uri=https://app.example.com/oauth/google/callback&
grant_type=authorization_code
Step 02

Resolve the customer ID and conversion action resource

Use the customer account that owns the conversion action, not just the manager account you log into every day. Store customer IDs without hyphens and store conversion actions as resource names. That gives every upload job a stable target and avoids the common mistake of sending a valid conversion to the wrong child account.

customer_id = "1234567890"
conversion_action_id = "987654321"

conversion_action =
  "customers/1234567890/conversionActions/987654321"
Step 03

Call the conversion upload endpoint

Batch uploads should be small enough to retry safely and large enough to avoid noisy per-order API calls. Use partial failure mode so one bad identifier does not block the whole batch. For documentation and internal runbooks, many teams describe this as posting to /customers/{id}/conversionUploads:upload; in the current REST API this maps to the customer uploadClickConversions method.

POST https://googleads.googleapis.com/v22/customers/{customer_id}:uploadClickConversions
developer-token: GOOGLE_ADS_DEVELOPER_TOKEN
login-customer-id: MANAGER_CUSTOMER_ID
authorization: Bearer ACCESS_TOKEN
content-type: application/json

{
  "partialFailure": true,
  "validateOnly": false,
  "debugEnabled": false,
  "conversions": []
}
Step 04

Send the base conversion payload

The first payload should be boring: one conversion action, one timestamp, one value, one currency, one order ID, one click identifier, and explicit consent. Get this accepted before adding enhanced identifiers. A minimal accepted payload proves account access, conversion action ownership, timestamp formatting, and click ID capture.

{
  "partialFailure": true,
  "conversions": [
    {
      "conversionAction": "customers/1234567890/conversionActions/987654321",
      "conversionDateTime": "2026-04-23 14:31:09+02:00",
      "conversionValue": 129.95,
      "currencyCode": "EUR",
      "orderId": "ORDER-10492",
      "gclid": "EAIaIQobChMI...",
      "conversionEnvironment": "WEB",
      "consent": {
        "adUserData": "GRANTED",
        "adPersonalization": "GRANTED"
      }
    }
  ]
}
Step 05

Add enhanced conversion identifiers

Enhanced Conversions depends on normalized and SHA-256 hashed user data. Normalize before hashing: lowercase emails, trim whitespace, remove separators from phone numbers, and format phone numbers consistently. Do not hash nulls, placeholders, or values collected without the right consent basis. Send multiple identifiers when you have them because match quality usually improves when email and phone arrive together.

import crypto from "node:crypto";

function sha256(value: string) {
  return crypto
    .createHash("sha256")
    .update(value.trim().toLowerCase())
    .digest("hex");
}

const userIdentifiers = [
  { hashedEmail: sha256("customer@example.com") },
  { hashedPhoneNumber: sha256("+491701234567") },
];
Step 06

Choose click ID first, enhanced identifiers as fallback

For web purchases, click identifiers remain the cleanest attribution key. Use GCLID when present, GBRAID for iOS app-originated click paths, and WBRAID for iOS web-originated click paths. When no click ID survives into the order, upload enhanced conversion identifiers so Google can attempt a user match. Keep the logic explicit, and never invent a click ID from session data.

const conversion = {
  conversionAction,
  conversionDateTime: order.paidAtGoogleAdsFormat,
  conversionValue: order.total,
  currencyCode: order.currency,
  orderId: order.id,
  conversionEnvironment: "WEB",
  consent: {
    adUserData: order.consent.ad_user_data,
    adPersonalization: order.consent.ad_personalization,
  },
};

if (order.gclid) conversion.gclid = order.gclid;
else if (order.gbraid) conversion.gbraid = order.gbraid;
else if (order.wbraid) conversion.wbraid = order.wbraid;
else conversion.userIdentifiers = userIdentifiers;
Schema

Payload structure

Google Ads field names differ slightly between REST JSON, client libraries, and internal event schemas. The table below uses snake_case labels because those are common in ecommerce data models, but your final API request should map them to the current Google Ads API casing for the method you call.

FieldRequiredPurposeExample
conversion_actionYesNames the Google Ads conversion action that should receive the event.customers/1234567890/conversionActions/987654321
conversion_date_timeYesTells Google when the conversion happened in the advertiser timezone.2026-04-23 14:31:09+02:00
conversion_valueRecommendedFeeds value-based bidding, ROAS reporting, and revenue diagnostics.129.95
currency_codeRequired with valueDefines the ISO currency for the uploaded conversion value.EUR
order_idRecommendedDeduplicates repeat uploads and joins diagnostics back to commerce records.ORDER-10492
user_identifiers.hashed_emailEnhanced fallbackMatches the conversion to signed-in Google users when click IDs are absent or incomplete.sha256(lowercase_trimmed_email)
user_identifiers.hashed_phone_numberEnhanced fallbackAdds a second durable first-party identifier for match quality.sha256(+491701234567)
address_infoOptionalProvides name and postal address signals when email or phone are unavailable.first_name, last_name, country_code, postal_code
gclidOne click ID or identifierAttributes standard web conversions to the Google click that produced the visit.EAIaIQobChMI...
gbraidConditionalHandles iOS app-related click paths where GCLID is not available.0AAAAA...
wbraidConditionalHandles iOS web click paths where privacy controls prevent a standard GCLID.CjwKCA...
consent settingsYes for governed regionsCarries ad user data and personalization choices into the upload.adUserData: GRANTED, adPersonalization: DENIED
Consent

Consent signals

Enhanced Conversions should not be treated as a way around consent. The upload must reflect the user choice your site collected. In Google’s consent model, the important ad fields are ad_user_data and ad_personalization. ad_user_data controls whether user data may be sent to Google for advertising purposes. ad_personalization controls whether that data may be used for personalized advertising. Your internal event can store these as a google-ads-consent object, then map them into the upload payload.

{
  "google-ads-consent": {
    "ad_user_data": "GRANTED",
    "ad_personalization": "DENIED"
  }
}

Consent Mode v2 should be integrated before the conversion upload layer, not bolted on afterward. The page-level consent state should be available before tags fire, persisted with the session, attached to the order or lead, and used by the server upload job. If consent is denied for ad_user_data, remove hashed email, hashed phone, and address_info from the payload. If ad_personalization is denied, pass that denial forward rather than assuming the platform will infer it from missing identifiers.

This matters operationally as well as legally. Diagnostics are easier to read when every uploaded conversion has an explicit consent state. A sudden drop in match rate can then be traced to actual consent mix, a CMP release, or missing identifiers instead of a vague suspicion that Google rejected the batch.

QA

Testing + validation

Start validation with validateOnly set to true, then send a controlled real upload with partial failure enabled. Once the API accepts the payload, move into Google Ads. Open the conversion action, inspect the diagnostics tab, and compare upload behavior against your backend event log. The goal is to prove not only that Google accepted the request, but that the conversion action is healthy enough to influence reporting and bidding.

Match rate

Watch the percentage of uploaded enhanced conversions Google can match. Use a practical guardrail — investigate when match rate moves ≥ 10 points down or stays ≤ your historical baseline for a full day. A weak match rate usually means identifiers are missing, not normalized before hashing, collected too late, or blocked by consent state.

Attribution lift

Compare reported conversions and value before and after the upload becomes stable. Lift should be evaluated over days, not minutes, because diagnostics and bidding feedback are delayed.

Diagnostic alerts

Review warnings for formatting, consent, duplicate order IDs, stale timestamps, missing click IDs, and unverified conversion actions. Fix these before judging campaign performance.

Conversion action status

Confirm the action is recording, included in account goals if intended, and not marked inactive, unverified, or recently edited in a way that changes optimization behavior.

Errors

Troubleshooting

Treat upload errors as data quality feedback. Log the Google request ID, customer ID, conversion action, order ID, selected click ID, consent state, and partial failure details. Without those fields, the same error can point to five different systems.

INVALID_USER_IDENTIFIER

The identifier is empty, malformed, unhashed, double-hashed, or not normalized before hashing. Rebuild hashing around clean lowercase email and E.164-style phone values.

CONVERSION_PRECEDES_AD_CLICK

The conversion timestamp is earlier than the click. Check timezone conversion, delayed payment capture, imported legacy orders, and server clocks.

UNAUTHENTICATED

The access token is expired, the refresh token was revoked, or the OAuth scope is wrong. Refresh the token and confirm the adwords scope is present.

PERMISSION_DENIED

The OAuth user or manager account cannot access the target customer or conversion action. Verify login-customer-id, customer hierarchy, and user permissions.

CLICK_NOT_FOUND

Google could not find a matching ad click for the supplied ID or identifiers. This is expected for non-Google traffic when debug checks are strict; filter by source and tune debugEnabled.

DUPLICATE_ORDER_ID

The same order ID was uploaded for the same conversion action. Keep order IDs stable for idempotency, but avoid resending corrected conversions as new purchases.

FAQ

FAQ

Do Enhanced Conversions replace the Google tag?

Not always. Enhanced Conversions for web commonly starts with the Google tag or GTM sending a conversion and order ID, then the API enhances that conversion with hashed user data. Server-side uploads are useful when the final conversion source is backend checkout, CRM, subscription billing, or a lead qualification system.

Should I upload every order or only Google Ads orders?

For enhanced conversion fallback workflows, many teams upload all eligible conversion events and let Google match what belongs to Google Ads traffic. Keep consent filtering in place and decide whether debug mode should surface expected CLICK_NOT_FOUND cases.

Can I send both GCLID and hashed email?

Yes. For web conversions, a click ID plus enhanced user identifiers is typically stronger than either signal alone. The important part is that the data describes the same conversion and was collected with appropriate consent.

How fast do diagnostics update?

Uploads return API acceptance quickly, but Google Ads diagnostics and reporting can lag. Evaluate status over at least a full day of normal traffic, and longer when conversion volume is low.

What timestamp should I use for delayed payments?

Use the time the conversion actually occurred according to your business definition. For ecommerce, that is usually paid order time, not first checkout start. Keep the timezone explicit so Google does not compare the conversion against the click incorrectly.

What consent values should I send?

Map your CMP or Consent Mode v2 state into ad_user_data and ad_personalization. When consent is denied, do not send personal identifiers and send the denied state so upload behavior matches the user choice.

Continue

Next reads

We use essential cookies to keep the site secure and functional. Analytics and third-party tags run only with your consent. See our Cookie Policy.

We use essential cookies to keep the site secure and functional. Analytics and third-party tags run only with your consent. See our Cookie Policy.