Upload Call Conversions

You can use the Google Ads API to upload offline call conversions into Google Ads, mapping to the Uploads conversion source in the Google Ads UI, followed by choosing Conversions from calls. It gives you more flexibility in associating calls with conversions.

A mobile click-to-call click cannot be uploaded as a conversion if there is no Google forwarding number attached to the call. Without a Google forwarding number, there is no way Google can be sure that the click led to a call and then to a conversion. If a click is uploaded like this, it will be ignored by the conversion action.

Code example

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

Java

private void runExample(
    GoogleAdsClient googleAdsClient,
    long customerId,
    String conversionActionId,
    String callerId,
    String callStartDateTime,
    double conversionValue) {
  // Create a call conversion by specifying currency as USD.
  CallConversion conversion =
      CallConversion.newBuilder()
          .setConversionAction(conversionActionId)
          .setCallerId(callerId)
          .setCallStartDateTime(callStartDateTime)
          .setConversionValue(conversionValue)
          .setCurrencyCode("USD")
          .build();

  // Uploads the call conversion to the API.
  try (ConversionUploadServiceClient conversionUploadServiceClient =
      googleAdsClient.getLatestVersion().createConversionUploadServiceClient()) {
    // Partial failure MUST be enabled for this request.
    UploadCallConversionsResponse response =
        conversionUploadServiceClient.uploadCallConversions(
            UploadCallConversionsRequest.newBuilder()
                .setCustomerId(String.valueOf(customerId))
                .setCustomerId(Long.toString(customerId))
                .addConversions(conversion)
                .setPartialFailure(true)
                .build());

    // Prints any partial failure errors returned.
    if (response.hasPartialFailureError()) {
      throw new RuntimeException(
          "Partial failure occurred " + response.getPartialFailureError().getMessage());
    }

    // Prints the result if valid.
    CallConversionResult result = response.getResults(0);
    System.out.printf(
        "Uploaded call conversion that occurred at '%' for caller ID '%' to the conversion"
            + " action with resource name '%'.%n",
        result.getCallStartDateTime(), result.getCallerId(), result.getConversionAction());
  }
}

C#

public void Run(GoogleAdsClient client, long customerId, string callerId,
    string callStartTime, string conversionTime, double conversionValue)
{
    // Get the ConversionUploadService.
    ConversionUploadServiceClient conversionUploadService =
        client.GetService(Services.V6.ConversionUploadService);

    // Create a call conversion by specifying currency as USD.
    CallConversion callConversion = new CallConversion()
    {
        CallerId = callerId,
        CallStartDateTime = callStartTime,
        ConversionDateTime = conversionTime,
        ConversionValue = conversionValue,
        CurrencyCode = "USD"
    };

    UploadCallConversionsRequest request = new UploadCallConversionsRequest()
    {
        CustomerId = customerId.ToString(),
        Conversions = { callConversion },
        PartialFailure = true
    };

    try
    {
        // Issues a request to upload the call conversion. The partialFailure parameter
        // is set to true, and validateOnly parameter to false as required by this method
        // call.
        UploadCallConversionsResponse response =
            conversionUploadService.UploadCallConversions(request);

        // Prints the result.
        CallConversionResult uploadedCallConversion = response.Results[0];
        Console.WriteLine($"Uploaded call conversion that occurred at " +
            $"'{uploadedCallConversion.CallStartDateTime}' for caller ID " +
            $"'{uploadedCallConversion.CallerId}' to the conversion action with " +
            $"resource name '{uploadedCallConversion.ConversionAction}'.");
    }
    catch (GoogleAdsException e)
    {
        Console.WriteLine("Failure:");
        Console.WriteLine($"Message: {e.Message}");
        Console.WriteLine($"Failure: {e.Failure}");
        Console.WriteLine($"Request ID: {e.RequestId}");
        throw;
    }
}

PHP

public static function runExample(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    int $conversionActionId,
    string $callerId,
    string $callStartDateTime,
    string $conversionDateTime,
    float $conversionValue
) {
    // Creates a call conversion by specifying currency as USD.
    $callConversion = new CallConversion([
        'conversion_action' =>
            ResourceNames::forConversionAction($customerId, $conversionActionId),
        'caller_id' => $callerId,
        'call_start_date_time' => $callStartDateTime,
        'conversion_date_time' => $conversionDateTime,
        'conversion_value' => $conversionValue,
        'currency_code' => 'USD',
    ]);

    // Issues a request to upload the call conversion.
    $conversionUploadServiceClient = $googleAdsClient->getConversionUploadServiceClient();
    $response = $conversionUploadServiceClient->uploadCallConversions(
        $customerId,
        [$callConversion],
        true
    );

    // 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())) {
        printf(
            "Partial failures occurred: '%s'.%s",
            $response->getPartialFailureError()->getMessage(),
            PHP_EOL
        );
    } else {
        // Prints the result if exists.
        /** @var CallConversionResult $uploadedCallConversion */
        $uploadedCallConversion = $response->getResults()[0];
        printf(
            "Uploaded call conversion that occurred at '%s' for caller ID '%s' to the "
            . "conversion action with resource name '%s'.%s",
            $uploadedCallConversion->getCallStartDateTime(),
            $uploadedCallConversion->getCallerId(),
            $uploadedCallConversion->getConversionAction(),
            PHP_EOL
        );
    }
}

Python

def main(
    client,
    customer_id,
    conversion_action_id,
    caller_id,
    call_start_date_time,
    conversion_date_time,
    conversion_value,

Ruby

def upload_call_conversion(customer_id, conversion_action_id, caller_id,
  call_start_date_time, conversion_date_time, conversion_value)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  # Create a call conversion by specifying currency as USD.
  call_conversion = client.resource.call_conversion do |c|
    c.conversion_action = client.path.conversion_action(
      customer_id, conversion_action_id)
    c.caller_id = caller_id
    c.call_start_date_time = call_start_date_time
    c.conversion_date_time = conversion_date_time
    c.conversion_value = conversion_value
    c.currency_code = "USD"
  end

  # Issues a request to upload the call conversion.
  response = client.service.conversion_upload.upload_call_conversions(
    customer_id: customer_id,
    conversions: [call_conversion],
    partial_failure: true
  )

  # Prints errors if any partial failure error is returned.
  if response.partial_failure_error
    failures = client.decode_partial_failure_error(response.partial_failure_error)
    failures.each do |failure|
      failure.errors.each do |error|
        human_readable_error_path = error
          .location
          .field_path_elements
          .map { |location_info|
            if location_info.index
              "#{location_info.field_name}[#{location_info.index}]"
            else
              "#{location_info.field_name}"
            end
          }.join(" > ")

        errmsg =  "error occured while adding operations " \
          "#{human_readable_error_path}" \
          " with value: #{error.trigger.string_value}" \
          " because #{error.message.downcase}"
        puts errmsg
      end
    end
  else
    # Print the result if valid.
    uploaded_call_conversion = response.results.first
    puts "Uploaded call conversion that occurred at " \
      "#{uploaded_call_conversion.call_start_date_time} " \
      "for caller ID " \
      "#{uploaded_call_conversion.caller_id} " \
      "to the conversion action with resource name " \
      "#{uploaded_call_conversion.conversion_action}"
  end
end

Perl

sub upload_call_conversion {
  my ($api_client, $customer_id, $conversion_action_id, $caller_id,
    $call_start_date_time, $conversion_date_time, $conversion_value)
    = @_;

  # Create a call conversion by specifying currency as USD.
  my $call_conversion =
    Google::Ads::GoogleAds::V6::Services::ConversionUploadService::CallConversion
    ->new({
      conversionAction =>
        Google::Ads::GoogleAds::V6::Utils::ResourceNames::conversion_action(
        $customer_id, $conversion_action_id
        ),
      callerId           => $caller_id,
      callStartDateTime  => $call_start_date_time,
      conversionDateTime => $conversion_date_time,
      conversionValue    => $conversion_value,
      currencyCode       => "USD"
    });

  # Issue a request to upload the call conversion.
  my $upload_call_conversions_response =
    $api_client->ConversionUploadService()->upload_call_conversions({
      customerId     => $customer_id,
      conversions    => [$call_conversion],
      partialFailure => "true"
    });

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

  # Print the result if valid.
  my $uploaded_call_conversion =
    $upload_call_conversions_response->{results}[0];
  if (%$uploaded_call_conversion) {
    printf "Uploaded call conversion that occurred at '%s' " .
      "for caller ID '%s' to the conversion action with resource name '%s'.\n",
      $uploaded_call_conversion->{callStartDateTime},
      $uploaded_call_conversion->{callerId},
      $uploaded_call_conversion->{conversionAction};
  }

  return 1;
}

Uploading CallConversion

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

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

  • The ConversionAction had a status of ENABLED at the time of the call.

  • The ConversionAction existed in the effective conversion account of the call's Google Ads account at the time of the call. If the account was not using cross-account conversion tracking at the time of the call, Google Ads will look for the ConversionAction in the account used to upload conversions. You can find your account's effective conversion tracking account under TOOLS & SETTINGS > Conversions in the Google Ads UI, or the conversion_tracking_setting attribute of Customer in the Google Ads API. However, keep in mind that this shows you the current effective conversion tracking account, which may differ from the effective conversion tracking account in place at the time of the call.

In addition, the following conditions must be met:

  • 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, e.g., 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 CallConversion

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

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

  • 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.

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