Upload Click Conversions

You can use the Google Ads API to upload offline click conversions into Google Ads, mapping to the Uploads conversion source in the Google Ads UI, followed by Conversions from clicks. It gives you more flexibility in associating clicks with conversions. You can track ads that led to sales in the offline world, such as over the phone or through a sales rep.

You must enable your website and lead-tracking system to capture and store the GCLID, the unique ID that Google Ads provides for every impression of a Google ad. If the click conversions are uploaded in the Google Ads UI, auto-tagging is automatically enabled so your website will start receiving the GCLID as a URL parameter. But this does not occur when using the Google Ads API, and you should enable auto-tagging by updating the auto_tagging_enabled attribute of Customer.

Code example

You need to associate your offline click conversions with a conversion action by passing the GCLID, conversion date time, conversion action resource name and optionally the conversion value and currency to ConversionUploadService:


private void runExample(
    GoogleAdsClient googleAdsClient,
    long customerId,
    long conversionActionId,
    String gclid,
    String conversionDateTime,
    Double conversionValue,
    Long conversionCustomVariableId,
    String conversionCustomVariableValue,
    String orderId) {
  // Gets the conversion action resource name.
  String conversionActionResourceName =
      ResourceNames.conversionAction(customerId, conversionActionId);

  // Creates the click conversion.
  ClickConversion.Builder clickConversionBuilder =

  if (conversionCustomVariableId != null && conversionCustomVariableValue != null) {
    // Sets the custom variable and value, if provided.
                ResourceNames.conversionCustomVariable(customerId, conversionCustomVariableId))

  if (orderId != null) {
    // Sets the order ID (unique transaction ID), if provided. An order ID is required in order to
    // upload enhancements as shown in the UploadConversionEnhancement example.

  ClickConversion clickConversion = clickConversionBuilder.build();

  // Creates the conversion upload service client.
  try (ConversionUploadServiceClient conversionUploadServiceClient =
      googleAdsClient.getLatestVersion().createConversionUploadServiceClient()) {
    // Uploads the click conversion. Partial failure should always be set to true.
    UploadClickConversionsResponse response =
                // Enables partial failure (must be true).

    // Prints any partial errors returned.
    if (response.hasPartialFailureError()) {
          "Partial error encountered: '%s'.%n", response.getPartialFailureError().getMessage());

    // Prints the result.
    ClickConversionResult result = response.getResults(0);
    // Only prints valid results.
    if (result.hasGclid()) {
          "Uploaded conversion that occurred at '%s' from Google Click ID '%s' to '%s'.%n",
          result.getConversionDateTime(), result.getGclid(), result.getConversionAction());


public void Run(GoogleAdsClient client, long customerId, long conversionActionId,
    string gclid, string conversionTime, double conversionValue)
    // Get the ConversionActionService.
    ConversionUploadServiceClient conversionUploadService =

    // Creates a click conversion by specifying currency as USD.
    ClickConversion clickConversion = new ClickConversion()
        ConversionAction = ResourceNames.ConversionAction(customerId, conversionActionId),
        Gclid = gclid,
        ConversionValue = conversionValue,
        ConversionDateTime = conversionTime,
        CurrencyCode = "USD"

        // Issues a request to upload the click conversion.
        UploadClickConversionsResponse response =
                new UploadClickConversionsRequest()
                    CustomerId = customerId.ToString(),
                    Conversions = { clickConversion },
                    PartialFailure = true,
                    ValidateOnly = false

        // Prints the result.
        ClickConversionResult uploadedClickConversion = response.Results[0];
        Console.WriteLine($"Uploaded conversion that occurred at " +
            $"'{uploadedClickConversion.ConversionDateTime}' from Google " +
            $"Click ID '{uploadedClickConversion.Gclid}' to " +
    catch (GoogleAdsException e)
        Console.WriteLine($"Message: {e.Message}");
        Console.WriteLine($"Failure: {e.Failure}");
        Console.WriteLine($"Request ID: {e.RequestId}");


public static function runExample(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    int $conversionActionId,
    string $gclid,
    string $conversionDateTime,
    float $conversionValue,
    ?string $conversionCustomVariableId,
    ?string $conversionCustomVariableValue
) {
    // Creates a click conversion by specifying currency as USD.
    $clickConversion = new ClickConversion([
        'conversion_action' =>
            ResourceNames::forConversionAction($customerId, $conversionActionId),
        'gclid' => $gclid,
        'conversion_value' => $conversionValue,
        'conversion_date_time' => $conversionDateTime,
        'currency_code' => 'USD'

    if (!is_null($conversionCustomVariableId) && !is_null($conversionCustomVariableValue)) {
        $clickConversion->setCustomVariables([new CustomVariable([
            'conversion_custom_variable' => ResourceNames::forConversionCustomVariable(
            'value' => $conversionCustomVariableValue

    // Issues a request to upload the click conversion.
    $conversionUploadServiceClient = $googleAdsClient->getConversionUploadServiceClient();
    /** @var UploadClickConversionsResponse $response */
    $response = $conversionUploadServiceClient->uploadClickConversions(

    // Prints the status message if any partial failure error is returned.
    // Note: The details of each partial failure error are not printed here, you can refer to
    // the example HandlePartialFailure.php to learn more.
    if (!is_null($response->getPartialFailureError())) {
            "Partial failures occurred: '%s'.%s",
    } else {
        // Prints the result if exists.
        /** @var ClickConversionResult $uploadedClickConversion */
        $uploadedClickConversion = $response->getResults()[0];
            "Uploaded click conversion that occurred at '%s' from Google Click ID '%s' " .
            "to '%s'.%s",


def main(
    """Creates a click conversion with a default currency of USD.

        client: An initialized GoogleAdsClient instance.
        customer_id: The client customer ID string.
        conversion_action_id: The ID of the conversion action to upload to.
        gclid: The Google Click Identifier ID.
        conversion_date_time: The the date and time of the conversion (should be
            after the click time). The format is 'yyyy-mm-dd hh:mm:ss+|-hh:mm',
            e.g. '2021-01-01 12:32:45-08:00'.
        conversion_value: The conversion value in the desired currency.
        conversion_custom_variable_id: The ID of the conversion custom
            variable to associate with the upload.
        conversion_custom_variable_value: The str value of the conversion custom
            variable to associate with the upload.
    click_conversion = client.get_type("ClickConversion")
    conversion_action_service = client.get_service("ConversionActionService")
    click_conversion.conversion_action = (
            customer_id, conversion_action_id
    click_conversion.gclid = gclid
    click_conversion.conversion_value = float(conversion_value)
    click_conversion.conversion_date_time = conversion_date_time
    click_conversion.currency_code = "USD"

    if conversion_custom_variable_id and conversion_custom_variable_value:
        conversion_custom_variable = client.get_type("CustomVariable")
        conversion_custom_variable.conversion_custom_variable = (
        conversion_custom_variable.value = conversion_custom_variable_value

    conversion_upload_service = client.get_service("ConversionUploadService")
    request = client.get_type("UploadClickConversionsRequest")
    request.customer_id = customer_id
    request.conversions = [click_conversion]
    request.partial_failure = True
    conversion_upload_response = (
    uploaded_click_conversion = conversion_upload_response.results[0]
        f"Uploaded conversion that occurred at "
        f'"{uploaded_click_conversion.conversion_date_time}" from '
        f'Google Click ID "{uploaded_click_conversion.gclid}" '
        f'to "{uploaded_click_conversion.conversion_action}"'


def upload_offline_conversion(
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  click_conversion = client.resource.click_conversion do |cc|
    cc.conversion_action = client.path.conversion_action(customer_id, conversion_action_id)
    cc.gclid = gclid
    cc.conversion_value = conversion_value.to_f
    cc.conversion_date_time = conversion_date_time
    cc.currency_code = 'USD'
    if conversion_custom_variable_id && conversion_custom_variable_value
      cc.custom_variables << client.resource.custom_variable do |cv|
        cv.conversion_custom_variable = client.path.conversion_custom_variable(
          customer_id, conversion_custom_variable_id)
        cv.value = conversion_custom_variable_value

  response = client.service.conversion_upload.upload_click_conversions(
    customer_id: customer_id,
    conversions: [click_conversion],
    partial_failure: true,
  if response.partial_failure_error.nil?
    result = response.results.first
    puts "Uploaded conversion that occurred at #{result.conversion_date_time} " \
      "from Google Click ID #{result.gclid} to #{result.conversion_action}."
    failures = client.decode_partial_failure_error(response.partial_failure_error)
    puts "Request failed. Failure details:"
    failures.each do |failure|
      failure.errors.each do |error|
        puts "\t#{error.error_code.error_code}: #{error.message}"


sub upload_offline_conversion {
  my (
    $api_client,                    $customer_id,
    $conversion_action_id,          $gclid,
    $conversion_date_time,          $conversion_value,
    $conversion_custom_variable_id, $conversion_custom_variable_value
  ) = @_;

  # Create a click conversion by specifying currency as USD.
  my $click_conversion =
      conversionAction =>
        $customer_id, $conversion_action_id
      gclid              => $gclid,
      conversionDateTime => $conversion_date_time,
      conversionValue    => $conversion_value,
      currencyCode       => "USD"

  if ($conversion_custom_variable_id && $conversion_custom_variable_value) {
    $click_conversion->{customVariables} = [
          conversionCustomVariable =>
            $customer_id, $conversion_custom_variable_id
          value => $conversion_custom_variable_value

  # Issue a request to upload the click conversion.
  my $upload_click_conversions_response =
      customerId     => $customer_id,
      conversions    => [$click_conversion],
      partialFailure => "true"

  # Print any partial errors returned.
  if ($upload_click_conversions_response->{partialFailureError}) {
    printf "Partial error encountered: '%s'.\n",

  # Print the result if valid.
  my $uploaded_click_conversion =
  if (%$uploaded_click_conversion) {
      "Uploaded conversion that occurred at '%s' from Google Click ID '%s' " .
      "to the conversion action with resource name '%s'.\n",

  return 1;

Import externally attributed conversions

If you use third-party tools or homegrown solutions to track conversions, then you may want to give Google Ads only part of the credit for the conversion. Sometimes, you may also want to distribute a conversion's credit across multiple clicks. Externally attributed conversion imports allow you to upload conversions with fractional credit assigned to each GCLID.

To upload fractional credits, you need to follow the upload_offline_conversion code example, then specify the external_attribution_model and external_attribution_credit attributes for the ExternalAttributionData when creating the ClickConversion.

Include cart data in conversions

You can include shopping cart information for a ClickConversion in the cart_data field, which consists of the following attributes:

  • merchant_id: The ID of the associated Merchant Center account.
  • feed_country_code: The ISO 3166 two-character region code of the Merchant Center feed.
  • feed_language_code: The ISO 639-1 language code of the Merchant Center feed.
  • local_transaction_cost: The sum of all transaction-level discounts, in the currency_code of the ClickConversion.
  • items: The items in the shopping cart.

Each item in items consists of the following attributes:

  • product_id: The ID of the product, sometimes referred to as the offer ID or item ID.
  • quantity: The quantity of the item.
  • unit_price: The unit price of the item.

Uploading ClickConversion

There are several requirements that must be met when uploading a ClickConversion.

To avoid a ConversionUploadError.INVALID_CONVERSION_ACTION error, the conversion_action attribute must refer to a ConversionAction where:

  • The ConversionActionType is UPLOAD_CLICKS.
  • The status of the ConversionAction is ENABLED.
  • The ConversionAction exists in the effective conversion account of the click's Google Ads account.
  • At the time of the click, conversion tracking was enabled in the effective conversion account of the click's Google Ads account.
  • Starting with v8 of the Google Ads API, the customer_id of the UploadClickConversionsRequest must be the customer ID of the owner_customer of each click conversion's conversion_action.

In addition, the following conditions must be met:

  • Starting with v8 of the Google Ads API, the customer_id of the UploadClickConversionsRequest must be the customer ID of the effective conversion tracking account of the click's Google Ads account. Otherwise, the conversion upload will result in a ConversionUploadError.INVALID_CUSTOMER_FOR_CLICK error.

  • The conversion_date_time must be after the impression happened, to avoid a ConversionUploadError.CONVERSION_PRECEDES_GCLID error.

  • The conversion_date_time must be before the click_through_lookback_window_days you specified for the ConversionAction, to avoid a ConversionUploadError.EXPIRED_GCLID error.

  • The conversion_value must be greater than or equal to zero.

  • The conversion_date_time must have a timezone specified, and the format is as yyyy-mm-dd hh:mm:ss+|-hh:mm, for example, 2019-01-01 12:32:45-08:00. The timezone can be for any valid value: it does not have to match the account's timezone.

Creating ClickConversion

A few things to keep in mind when creating a ClickConversion:

  • The partial_failure attribute of the UploadClickConversionsRequest should always be set to true. Follow the partial failures guidelines when handlling valid and failed operations simultaneously.

  • Although duplicate uploads of a conversion (same GCLID, name and time) are permitted, only the first instance is recorded.

  • Uploaded conversions will be reflected in reports for the impression date of the original click, not the date of the upload request or the date of the conversion_date_time of the ClickConversion.

  • We recommend you wait 6 hours after creating the ConversionAction before uploading.

  • It takes up to 3 hours for imported conversion statistics to appear in your Google Ads account for last-click attribution. For other search attribution models, it can take longer than 3 hours.

  • When uploading click conversions for multiple accounts, you can specify the customer_id of a common manager account and include conversions with GCLIDs from across multiple accounts. A conversion is attributed to the proper account based on the origin of its GCLID.

    Starting with v8, this approach will succeed only if both of the following conditions are met:

    1. The effective conversion account of the client account of the GCLID is set to the manager specified in the request's customer_id.
    2. The conversion_action of the ClickConversion is owned by the manager specified in the request's customer_id.
  • When uploading click conversions with cross-account conversion tracking enabled, the conversion action must be in the manager account, rather than in the account associated with the GCLID.

  • If you plan to upload first-party data adjustments for enhanced conversions, you must provide an order_id for each ClickConversion.