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:


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 =

  // Uploads the call conversion to the API.
  try (ConversionUploadServiceClient conversionUploadServiceClient =
      googleAdsClient.getLatestVersion().createConversionUploadServiceClient()) {
    // Partial failure MUST be enabled for this request.
    UploadCallConversionsResponse response =

    // 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);
        "Uploaded call conversion that occurred at '%' for caller ID '%' to the conversion"
            + " action with resource name '%'.%n",
        result.getCallStartDateTime(), result.getCallerId(), result.getConversionAction());


public void Run(GoogleAdsClient client, long customerId, string callerId,
    string callStartTime, string conversionTime, double conversionValue)
    // Get the ConversionUploadService.
    ConversionUploadServiceClient 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

        // 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 =

        // 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($"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 $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(

    // 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 CallConversionResult $uploadedCallConversion */
        $uploadedCallConversion = $response->getResults()[0];
            "Uploaded call conversion that occurred at '%s' for caller ID '%s' to the "
            . "conversion action with resource name '%s'.%s",


def main(
    """Imports offline call conversion values for calls related to your ads.

        client: An initialized GoogleAdsClient instance.
        customer_id: The client customer ID string.
        conversion_action_id: The ID of the conversion action to upload to.
        caller_id: The caller ID from which this call was placed. Caller ID is
            expected to be in E.164 format with preceding '+' sign,
            e.g. '+16502531234'.
        call_start_date_time: The date and time at which the call occurred. The
            format is 'yyyy-mm-dd hh:mm:ss+|-hh:mm',
            e.g. '2019-01-01 12:32:45-08:00'.
        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. '2019-01-01 12:32:45-08:00'.
        conversion_value: The conversion value in the desired currency.
    # Get the ConversionUploadService client.
    conversion_upload_service = client.get_service(
        "ConversionUploadService", version="v6"

    # Create a call conversion in USD currency.
    call_conversion = client.get_type("CallConversion", version="v6")
    call_conversion.conversion_action = client.get_service(
        "ConversionActionService", version="v6"
    ).conversion_action_path(customer_id, conversion_action_id)
    call_conversion.caller_id = caller_id
    call_conversion.call_start_date_time = call_start_date_time
    call_conversion.conversion_date_time = conversion_date_time
    call_conversion.conversion_value = conversion_value
    call_conversion.currency_code = "USD"

        # Issue a request to upload the call conversion.
        upload_call_conversions_response = conversion_upload_service.upload_call_conversions(
            customer_id, [call_conversion], partial_failure=True

        # Print any partial errors returned.
        if upload_call_conversions_response.partial_failure_error:
                "Partial error ocurred: "

        # Print the result if valid.
        uploaded_call_conversion = upload_call_conversions_response.results[0]
        if uploaded_call_conversion.call_start_date_time:
                "Uploaded call conversion that occurred at "
                f"'{uploaded_call_conversion.call_start_date_time}' "
                f"for caller ID '{uploaded_call_conversion.caller_id}' "
                "to the conversion action with resource name "
    except GoogleAdsException as ex:
            f"Request with ID '{ex.request_id}'' failed with status "
            f"'{ex.error.code().name}' and includes the following errors:"
        for error in ex.failure.errors:
            print(f"\tError with message '{error.message}'.")
            if error.location:
                for field_path_element in error.location.field_path_elements:
                    print(f"\t\tOn field: {field_path_element.field_name}")


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"

  # 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
          .map { |location_info|
            if location_info.index
          }.join(" > ")

        errmsg =  "error occured while adding operations " \
          "#{human_readable_error_path}" \
          " with value: #{error.trigger.string_value}" \
          " because #{error.message.downcase}"
        puts errmsg
    # 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 " \


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 =
      conversionAction =>
        $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 =
      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",

  # Print the result if valid.
  my $uploaded_call_conversion =
  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",

  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 ConversionActionType is UPLOAD_CALLS.
  • 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 call, conversion tracking was enabled in the effective conversion account of the call's Google Ads account.

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